[BZOJ3438][洛谷P1361]小M的作物
题目大意:
有A、B两个集合和n个物品,每个物品只能放在一个集合里。每个物品放在不同集合内能获得不同价值。
有一些物品,如果它们同时放在一个集合内,则会产生新的价值(A和B中都有且不一定相同(c1和c2))。有若干这样的关系。
现在让你求最大总价值。
解题思路:
最大权闭合子图。
首先拆点,把点i拆成xi和yi
从S向每个xi连容量为“其放在集合A中的价值”的边,从xi向yi连容量为inf的边,从yi向T连容量为“其放在集合B中的价值”的边。
对于每个关系,新建节点p1,p2。从S向p1连容量为c1的边,从p1向每个有关系的y点连容量为inf的边;从p2向T连容量为c2的边,从每个有关系的x点向p2连容量为inf的边。
然后用总价值(包括关系中的c1和c2)减去最小割即可。
C++ Code:
#include<cstdio> #include<cctype> #include<cstring> #include<queue> const int S=0,T=40003,inf=0x3fffffff; inline int readint(){ int c=getchar(),d=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } int n,m,head[40333],cnt=1,level[40333],iter[40333],mrsrz,nx[40333]; struct edge{ int to,nxt,cap; }e[1700005]; inline void addedge(int u,int v,int t){ e[++cnt]=(edge){v,head[u],t}; head[u]=cnt; e[++cnt]=(edge){u,head[v],0}; head[v]=cnt; } std::queue<int>q; void bfs(){ level[S]=1; for(q.push(S);!q.empty();){ int u=q.front(); q.pop(); for(int i=head[u];~i;i=e[i].nxt) if(e[i].cap&&!~level[e[i].to]){ level[e[i].to]=level[u]+1; q.push(e[i].to); } } } inline int min(int a,int b){return a<b?a:b;} int dfs(int u,int f){ if(!f||u==T)return f; for(int& i=iter[u];~i;i=e[i].nxt) if(e[i].cap&&level[e[i].to]>level[u]){ int d=dfs(e[i].to,min(f,e[i].cap)); if(d){ e[i].cap-=d; e[i^1].cap+=d; return d; }else level[e[i].to]=-1; } return 0; } int dinic(){ for(int flow=0,f;;){ memset(level,-1,sizeof nx); if(bfs(),!~level[T])return flow; memcpy(iter,head,sizeof nx); while(f=dfs(S,inf))flow+=f; } } int main(){ #ifdef LOCALJUDGE freopen("input.txt","r",stdin); #endif int ans=0; memset(head,-1,sizeof head); n=readint(); for(int i=1;i<=n;++i){ int p=readint(); ans+=p; addedge(S,i,p); } for(int i=1;i<=n;++i)addedge(i,i+n,inf); for(int i=1;i<=n;++i){ int p=readint(); ans+=p; addedge(i+n,T,p); } mrsrz=n<<1; for(int k=readint();k--;){ int m=readint(),c1=readint(),c2=readint(); ans+=c1+c2; for(int i=1;i<=m;++i)nx[i]=readint(); addedge(S,++mrsrz,c1); for(int i=1;i<=m;++i)addedge(mrsrz,nx[i],inf); addedge(++mrsrz,T,c2); for(int i=1;i<=m;++i)addedge(nx[i],mrsrz,inf); } printf("%d\n",ans-dinic()); return 0; }