首页 > 其他 > 详细

51nod1325 两棵树的问题

时间:2020-06-05 21:03:28      阅读:42      评论:0      收藏:0      [点我收藏+]

题意

先枚举一个点必须选,设该点为\(x\)

将两棵树都以\(x\)为根,对于点\(y\),如果选\(y\)必须要选\(fa_y\),于是就变成了了最大权闭合子图。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=55;
const int inf=1e9;
int n,S,T,ans;
int val[maxn];
inline int read()
{
    char c=getchar();int res=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘)res=res*10+c-‘0‘,c=getchar();
    return res*f;
}
struct Edge
{
	int cnt_edge;
	int head[maxn],to[maxn<<1],nxt[maxn<<1],fa[maxn];
	inline void add_edge(int u,int v)
	{
		nxt[++cnt_edge]=head[u];
		head[u]=cnt_edge;
		to[cnt_edge]=v;
	}
}E1,E2;
void dfs(int x,Edge& E)
{
	for(int i=E.head[x];i;i=E.nxt[i])
	{
		int y=E.to[i];
		if(y==E.fa[x])continue;
		E.fa[y]=x;dfs(y,E);
	}
}
struct Dinic
{
	int cnt_edge;
	int head[maxn],nxt[maxn<<3],to[maxn<<3],flow[maxn<<3],cur[maxn],dep[maxn];
	inline void clear()
	{
		memset(head,0,sizeof(head));
		cnt_edge=1;
	}
	inline void add_edge(int u,int v,int w)
	{
		nxt[++cnt_edge]=head[u];
		head[u]=cnt_edge;
		to[cnt_edge]=v;
		flow[cnt_edge]=w;
	}
	inline void addflow(int u,int v,int w){add_edge(u,v,w),add_edge(v,u,0);}
	inline bool bfs()
	{
		memset(dep,0,sizeof(dep));
		for(int i=0;i<=n+1;i++)cur[i]=head[i];
		queue<int>q;
		q.push(S);dep[S]=1;
		while(!q.empty())
		{
			int x=q.front();q.pop();
			for(int i=head[x];i;i=nxt[i])
			{
				int y=to[i];
				if(dep[y]||!flow[i])continue;
				dep[y]=dep[x]+1;q.push(y);
			}
		}
		return dep[T]>0;
	}
	int dfs(int x,int goal,int lim)
	{
		if(x==goal||!lim)return lim;
		int res=lim;
		for(int i=cur[x];i;i=nxt[i])
		{
			cur[x]=i;
			int y=to[i];
			if(dep[y]!=dep[x]+1||!flow[i])continue;
			int tmp=dfs(y,goal,min(res,flow[i]));
			if(!tmp)dep[y]=0;
			flow[i]-=tmp,flow[i^1]+=tmp,res-=tmp;
			if(!res)break;
		}
		return lim-res;
	}
	inline int dinic()
	{
		int res=0;
		while(bfs())res+=dfs(S,T,inf);
		return res;
	}
}e;
inline void solve(int root)
{
	for(int i=1;i<=n;i++)E1.fa[i]=E2.fa[i]=0;
	dfs(root,E1),dfs(root,E2);
	e.clear();
	for(int i=1;i<=n;i++)
	{
		if(E1.fa[i])e.addflow(i,E1.fa[i],inf);
		if(E2.fa[i]&&E2.fa[i]!=E1.fa[i])e.addflow(i,E2.fa[i],inf);
	}
	int res=0;
	for(int i=1;i<=n;i++)
		if(val[i]>=0)res+=val[i],e.addflow(S,i,val[i]);
		else e.addflow(i,T,-val[i]);
	ans=max(ans,res-e.dinic());
}
int main()
{
	n=read();
	S=0,T=n+1;
	for(int i=1;i<=n;i++)val[i]=read();
	for(int i=1;i<n;i++)
	{
		int u=read()+1,v=read()+1;
		E1.add_edge(u,v),E1.add_edge(v,u);
	}
	for(int i=1;i<n;i++)
	{
		int u=read()+1,v=read()+1;
		E2.add_edge(u,v),E2.add_edge(v,u);
	}	
	for(int i=1;i<=n;i++)solve(i);
	printf("%d",ans);
	return 0;
}

51nod1325 两棵树的问题

原文:https://www.cnblogs.com/nofind/p/13051610.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!