分析:枚举根结点,每次考虑必然包含根结点的子图。如果i在图中,则i在两棵树中的父亲也必然在子图中,所以从i向两个父亲各连一条边,问题就转化为求最大权闭合子图了,每次枚举根结点更新答案即可。
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 #include<stack> 5 #include<cstdio> 6 #include<cstring> 7 using namespace std; 8 const int maxn=55,INF=1e9; 9 struct Edge{ 10 int from,to,cap,flow; 11 Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} 12 }; 13 struct ISAP{ 14 int n,s,t; 15 vector<Edge> edges; 16 vector<int> G[maxn]; 17 bool vis[maxn]; 18 int d[maxn]; 19 int cur[maxn]; 20 int p[maxn]; 21 int num[maxn]; 22 23 void init(int n){ 24 this->n=n; 25 edges.clear(); 26 for(int i=0;i<n;i++)G[i].clear(); 27 } 28 29 void AddEdge(int from,int to,int cap){ 30 edges.push_back(Edge(from,to,cap,0)); 31 edges.push_back(Edge(to,from,0,0)); 32 G[from].push_back(edges.size()-2); 33 G[to].push_back(edges.size()-1); 34 } 35 36 void BFS(){ 37 memset(vis,0,sizeof(vis)); 38 queue<int> Q; 39 Q.push(t); 40 d[t]=0; 41 vis[t]=1; 42 while(!Q.empty()){ 43 int x=Q.front();Q.pop(); 44 for(int i=0;i<G[x].size();i++){ 45 Edge &e=edges[G[x][i]^1]; 46 if(e.flow==e.cap)continue; 47 if(!vis[e.from]){ 48 vis[e.from]=1; 49 d[e.from]=d[x]+1; 50 Q.push(e.from); 51 } 52 } 53 } 54 } 55 56 int Augment(){ 57 int x=t,a=INF; 58 while(x!=s){ 59 Edge &e=edges[p[x]]; 60 a=min(a,e.cap-e.flow); 61 x=edges[p[x]].from; 62 } 63 x=t; 64 while(x!=s){ 65 edges[p[x]].flow+=a; 66 edges[p[x]^1].flow-=a; 67 x=edges[p[x]].from; 68 } 69 return a; 70 } 71 72 int Maxflow(int s,int t){ 73 this->s=s;this->t=t; 74 int flow=0; 75 BFS(); 76 memset(num,0,sizeof(num)); 77 for(int i=0;i<n;i++)num[d[i]]++; 78 int x=s; 79 memset(cur,0,sizeof(cur)); 80 while(d[s]<n){ 81 if(x==t){ 82 flow+=Augment(); 83 x=s; 84 } 85 int ok=0; 86 for(int i=cur[x];i<G[x].size();i++){ 87 Edge &e=edges[G[x][i]]; 88 if(e.cap>e.flow&&d[x]==d[e.to]+1){ 89 ok=1; 90 p[e.to]=G[x][i]; 91 cur[x]=i; 92 x=e.to; 93 break; 94 } 95 } 96 if(!ok){ 97 int m=n-1; 98 for(int i=0;i<G[x].size();i++){ 99 Edge &e=edges[G[x][i]]; 100 if(e.cap>e.flow)m=min(m,d[e.to]); 101 } 102 if(--num[d[x]]==0)break; 103 num[d[x]=m+1]++; 104 cur[x]=0; 105 if(x!=s)x=edges[p[x]].from; 106 } 107 } 108 return flow; 109 } 110 }isap; 111 112 int v[maxn],s,t,n; 113 int G[2][maxn][maxn],p[2][maxn]; 114 void buildtree(int root,int idx){ 115 for(int i=0;i<n;i++){ 116 if(G[idx][root][i]&&p[idx][root]!=i){ 117 p[idx][i]=root; 118 buildtree(i,idx); 119 } 120 } 121 } 122 void AddAllEdge(){ 123 for(int i=0;i<n;i++){ 124 if(v[i]>0)isap.AddEdge(s,i,v[i]); 125 else if(v[i]<0)isap.AddEdge(i,t,-v[i]); 126 if(p[0][i]==i)continue; 127 isap.AddEdge(i,p[0][i],INF); 128 if(p[0][i]!=p[1][i]); 129 isap.AddEdge(i,p[1][i],INF); 130 } 131 } 132 133 int main(){ 134 // freopen("e:\in.txt","r",stdin); 135 scanf("%d",&n); 136 s=n,t=n+1; 137 memset(G,0,sizeof(G)); 138 int a,b,sum=0,ans=0; 139 for(int i=0;i<n;i++){scanf("%d",&v[i]);sum+=v[i]>0?v[i]:0;} 140 for(int idx=0;idx<2;idx++){ 141 for(int i=0;i<n-1;i++){ 142 scanf("%d%d",&a,&b); 143 G[idx][a][b]=1; 144 G[idx][b][a]=1; 145 } 146 } 147 for(int i=0;i<n;i++){ 148 p[0][i]=i;p[1][i]=i; 149 buildtree(i,0);buildtree(i,1); 150 isap.init(n+2); 151 AddAllEdge(); 152 ans=max(ans,sum-isap.Maxflow(s,t)); 153 } 154 printf("%d ",ans); 155 return 0; 156 }