【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 }    

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/10582474.html