【xsy2193】Wallace 最大权闭合子图
题目大意:给你一棵$n$个节点的树$a$,每个点有一个点权$val_i$,同时给你另一棵$n$个节点的树$b$。
现在你需要在树$a$上找一个联通块,满足这些点在树$b$上也是连通的,同时树$a$的这个联通块的点权和要最大。
数据范围:$n≤50$,$-1000≤val_i≤1000$。
我们考虑钦定一个点作为跟,不妨设当前钦定的根为$x$。
我们发现,如果要选择点$y$,那么由点$y$至$x$的路径上的点都需要选(无论是树$a$还是树$b$)
然后这个就变成了一个经典的最大权闭合子图问题
直接最小割判定即可。
时间复杂度:玄学
1 #include<bits/stdc++.h> 2 #define M 320 3 #define N 52 4 #define INF 19890604 5 using namespace std; 6 7 struct edge{int u,v,next;}e[M]={0}; int head[M]={0},use=0; 8 void add(int x,int y,int z){e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use++;} 9 void Add(int x,int y,int z){add(x,y,z); add(y,x,0);} 10 11 int dis[N]={0},S,T; queue<int> q; 12 13 bool bfs(){ 14 memset(dis,0,sizeof(dis)); 15 q.push(S); dis[S]=1; 16 while(!q.empty()){ 17 int u=q.front(); q.pop(); 18 for(int i=head[u];~i;i=e[i].next) 19 if(e[i].v&&dis[e[i].u]==0){ 20 dis[e[i].u]=dis[u]+1; 21 q.push(e[i].u); 22 } 23 } 24 return dis[T]; 25 } 26 27 int dfs(int x,int flow){ 28 if(x==T) return flow; int sum=0; 29 for(int i=head[x];~i;i=e[i].next) 30 if(e[i].v&&dis[x]+1==dis[e[i].u]){ 31 int k=dfs(e[i].u,min(flow,e[i].v)); 32 e[i].v-=k; e[i^1].v+=k; 33 sum+=k; flow-=k; 34 if(flow==0) return sum; 35 } 36 if(flow==0) dis[x]=-1; 37 return sum; 38 } 39 40 int dinic(){int res=0; while(bfs()) res+=dfs(S,1<<30); return res;} 41 42 vector<int> G1[N],G2[N]; 43 int val[N]={0},f1[N]={0},f2[N]={0},n; 44 45 void dfs(int x,int fa,vector<int> G[],int f[]){ 46 f[x]=fa; if(fa) Add(x,fa,INF); 47 for(int i=0;i<G[x].size();i++) 48 if(G[x][i]!=fa) dfs(G[x][i],x,G,f); 49 } 50 51 int solve(int x){ 52 memset(head,-1,sizeof(head)); use=0; 53 dfs(x,0,G1,f1); 54 dfs(x,0,G2,f2); 55 S=0; T=n+1; 56 for(int i=1;i<=n;i++) 57 if(val[i]>0) Add(S,i,val[i]); 58 else Add(i,T,-val[i]); 59 return dinic(); 60 } 61 62 int main(){ 63 int sum=0; scanf("%d",&n); 64 for(int i=1;i<=n;i++) scanf("%d",val+i),sum+=max(0,val[i]); 65 for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),x++,y++,G1[x].push_back(y),G1[y].push_back(x); 66 for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),x++,y++,G2[x].push_back(y),G2[y].push_back(x); 67 68 int maxn=0; 69 for(int i=1;i<=n;i++) 70 maxn=max(maxn,sum-solve(i)); 71 cout<<maxn<<endl; 72 }