51nod1325 两棵树的问题

$n \leq 50$的两棵树,同编号的点有同个点权,问如何选一个点集,使得这个点集里的点在两棵树内都连通,且总点权最大,输出最大点权和。

枚举一个点在答案里,然后把树以它为根,此时选儿子一定要选父亲,构成最大权闭合子图。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 //#include<time.h>
  5 //#include<complex>
  6 //#include<set>
  7 //#include<queue>
  8 #include<algorithm>
  9 #include<stdlib.h>
 10 using namespace std;
 11 
 12 #define LL long long
 13 int qread()
 14 {
 15     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
 16     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
 17 }
 18 
 19 //Pay attention to '-' , LL and double of qread!!!!
 20 
 21 int n,m;
 22 #define maxn 111
 23 #define maxm 1111
 24 struct Edge{int to,next,flow,cap;};
 25 struct Network
 26 {
 27     Edge edge[maxm]; int first[maxn],le,n;
 28     void clear(int N) {le=2; memset(first,0,sizeof(first)); n=N;}
 29     void in(int x,int y,int cap) {Edge &e=edge[le]; e.to=y; e.cap=cap; e.flow=0; e.next=first[x]; first[x]=le++;}
 30     void insert(int x,int y,int cap) {in(x,y,cap); in(y,x,0);}
 31     int dis[maxn]; int que[maxn],cur[maxn],head,tail,s,t;
 32     bool bfs()
 33     {
 34         memset(dis,0,sizeof(dis)); dis[s]=1;
 35         head=tail=0; que[tail++]=s;
 36         while (head!=tail)
 37         {
 38             int x=que[head++];
 39             for (int i=first[x];i;i=edge[i].next)
 40             {
 41                 Edge &e=edge[i];
 42                 if (!dis[e.to] && e.cap>e.flow)
 43                 {
 44                     dis[e.to]=dis[x]+1;
 45                     que[tail++]=e.to;
 46                 }
 47             }
 48         }
 49         return dis[t];
 50     }
 51     int dfs(int x,int a)
 52     {
 53         if (x==t || !a) return a;
 54         int flow=0,f;
 55         for (int &i=cur[x];i;i=edge[i].next)
 56         {
 57             Edge &e=edge[i];
 58             if (dis[e.to]==dis[x]+1 && (f=dfs(e.to,min(e.cap-e.flow,a)))>0)
 59             {
 60                 flow+=f; e.flow+=f;
 61                 edge[i^1].flow-=f; a-=f;
 62                 if (!a) break;
 63             }
 64         }
 65         return flow;
 66     }
 67     int Dinic(int S,int T)
 68     {
 69         s=S; t=T;
 70         int ans=0;
 71         while (bfs())
 72         {
 73             for (int i=1;i<=n;i++) cur[i]=first[i];
 74             ans+=dfs(s,0x3f3f3f3f);
 75         }
 76         return ans;
 77     }
 78     bool vis[maxn];
 79     void dfs(int x)
 80     {
 81         vis[x]=1;
 82         for (int i=first[x];i;i=edge[i].next)
 83         {
 84             Edge &e=edge[i];
 85             if (e.cap>e.flow && !vis[e.to]) dfs(e.to);
 86         }
 87     }
 88 }g;
 89 
 90 struct EE{int to,next;};
 91 struct Tree
 92 {
 93     EE edge[maxn<<1]; int first[maxn],le;
 94     Tree() {le=2;}
 95     void in(int x,int y) {EE &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
 96     void insert(int x,int y) {in(x,y); in(y,x);}
 97 }t[2];
 98 
 99 int ss[maxn];
100 void dfs(int p,int x,int fa)
101 {
102     for (int i=t[p].first[x];i;i=t[p].edge[i].next)
103     {
104         EE &e=t[p].edge[i]; if (e.to==fa) continue;
105         g.insert(e.to,x,0x3f3f3f3f); dfs(p,e.to,x);
106     }
107 }
108 
109 int main()
110 {
111     n=qread(); int sum=0;
112     for (int i=1;i<=n;i++) {ss[i]=qread(); if (ss[i]>0) sum+=ss[i];}
113     for (int i=1;i<n;i++) t[0].insert(qread()+1,qread()+1);
114     for (int i=1;i<n;i++) t[1].insert(qread()+1,qread()+1);
115     int s=n+1,t=s+1;
116     int ans=0;
117     for (int i=1;i<=n;i++)
118     {
119         g.clear(t);
120         dfs(0,i,0); dfs(1,i,0);
121         for (int j=1;j<=n;j++) if (ss[j]>0) g.insert(s,j,ss[j]);
122         else g.insert(j,t,-ss[j]);
123         ans=max(ans,sum-g.Dinic(s,t));
124     }
125     printf("%d\n",ans);
126     return 0;
127 }
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/8945182.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值