51nod 1325 两棵树的问题 最大权闭合子图
2017-12-24 20:58
369 查看
题意
有两颗各含N个点的无根树,每棵树中点分别被编号为0,1,2,….,N-1;注意两棵树并不保证同构。另外给一个N长的整数数组Score[],记录N个编号的得分,Score中的每个元素可正可负。
问题的任务是寻找 集合{0,1,2,3,4,…,N-1}的一个最优子集subset,要求满足以下条件:
1)在第一棵树中,subset中包含的编号对应的点能构成一个连通的子图;即去掉这棵树中所有subset中不包含的点后,剩下的点依然是一棵连通的树。
2)在第二棵树中,subset中包含的编号对应的点也能构成一个连通的子图;
3)使subset包含编号的总得分尽可能的大;即SUM{ Score[i] | i∈subset }能取到尽可能大的值。
输出这个subset包含编号的总分的最大值。
2<=N<=50,-1000<=Score[i]<=1000
分析
首先我们可以枚举两棵子树的根,然后继续搞事。注意到如果选了点x,那么在每一棵树上x到根路径上的所有点都要选。我们可以把这看成一个限制关系,如果选了x就一定要选x在两棵树中的父亲。然后直接上最大权闭合子图即可。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int N=55; const int inf=1000000000; int n,cnt,last ,ls1 ,ls2 ,cur ,dis ,s,t,val ; struct edge{int to,next,c;}e[N*N*10]; queue<int> que; int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void addedge(int u,int v,int c) { e[++cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt; e[++cnt].to=u;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt; } void build(int x,int fa,int op) { if (fa) addedge(x,fa,inf); if (op==1) { for (int i=ls1[x];i;i=e[i].next) if (e[i].to!=fa) build(e[i].to,x,op); } else { for (int i=ls2[x];i;i=e[i].next) if (e[i].to!=fa) build(e[i].to,x,op); } } bool bfs() { for (int i=s;i<=t;i++) dis[i]=0; while (!que.empty()) que.pop(); dis[s]=1;que.push(s); while (!que.empty()) { int u=que.front();que.pop(); for (int i=last[u];i;i=e[i].next) if (e[i].c&&!dis[e[i].to]) { dis[e[i].to]=dis[u]+1; if (e[i].to==t) return 1; que.push(e[i].to); } } return 0; } int dfs(int x,int maxf) { if (x==t||!maxf) return maxf; int ret=0; for (int &i=cur[x];i;i=e[i].next) if (e[i].c&&dis[e[i].to]==dis[x]+1) { int f=dfs(e[i].to,min(e[i].c,maxf-ret)); e[i].c-=f; e[i^1].c+=f; ret+=f; if (maxf==ret) break; } return ret; } int dinic() { int ans=0; while (bfs()) { for (int i=s;i<=t;i++) cur[i]=last[i]; ans+=dfs(s,inf); } return ans; } int main() { n=read(); for (int i=1;i<=n;i++) val[i]=read(); for (int i=1;i<n;i++) { int x=read()+1,y=read()+1; e[++cnt].to=y;e[cnt].next=ls1[x];ls1[x]=cnt; e[++cnt].to=x;e[cnt].next=ls1[y];ls1[y]=cnt; } for (int i=1;i<n;i++) { int x=read()+1,y=read()+1; e[++cnt].to=y;e[cnt].next=ls2[x];ls2[x]=cnt; e[++cnt].to=x;e[cnt].next=ls2[y];ls2[y]=cnt; } s=0;t=n+1;int tmp=cnt; if (!(tmp&1)) tmp++; int ans=0; for (int r1=1;r1<=n;r1++) for (int r2=1;r2<=n;r2++) { int sum=0;cnt=tmp; for (int i=s;i<=t;i++) last[i]=0; for (int i=1;i<=n;i++) if (val[i]>0) sum+=val[i],addedge(s,i,val[i]); else addedge(i,t,-val[i]); build(r1,0,1); build(r2,0,2); sum-=dinic(); ans=max(ans,sum); } printf("%d",ans); return 0; }
相关文章推荐
- 【51nod 1325】两棵树的问题
- Wiki 1233(太空飞行计划问题-最大权闭合子图)
- [SWUSTOJ1737] 太空飞行计划问题(最大权闭合子图,记录路径)
- PowerOJ 1737 网络流24题之二 太空飞行计划问题(最大权闭合子图)
- hdu 3879 Base Station bzoj 1497 最大获利问题 最大权闭合子图
- 网络流24题 太空飞行计划问题___最大权闭合子图
- Wiki 1233(太空飞行计划问题-最大权闭合子图)
- 洛谷 P2762 太空飞行计划问题 P3410 拍照【最大权闭合子图】题解+代码
- 51nod 1551 集合交易 匈牙利算法+最大权闭合子图
- 洛谷 P2762 太空飞行计划问题 【最大权闭合子图+最小割】
- hdu5772-String problem(最大权闭合子图问题)
- Cogs 734. [网络流24题] 方格取数问题(最大闭合子图)
- poj 2987 Firing 最大权闭合子图
- TJU 2944 Mussy Paper 最大权闭合子图
- POJ 2987 - Firing 比较完善的最大权闭合子图..维护两个最优值...
- 【XSY1996】【BZOJ1565】【NOI2009】植物大战僵尸 网络流 最大权闭合子图
- gift 分数规划的最大权闭合子图
- BZOJ 1497 最大权闭合子图
- poj 2987 Firing 最大权闭合子图
- bzoj 1497(最小割,最大权闭合子图)