51nod1325 两棵树的问题
题意
先枚举一个点必须选,设该点为\(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;
}