[BZOJ1280]Emmy卖猪pigs
题目大意:
Emmy在一个养猪场工作。这个养猪场有M个锁着的猪圈,但Emmy并没有钥匙。顾客会到养猪场来买猪,一个接着一个。每一位顾客都会有一些猪圈的钥匙,他们会将这些猪圈打开并买走固定数目的猪。 所有顾客有的钥匙和他们需要买猪的数量在事先都告诉了Emmy,于是Emmy要订一个计划,使得卖出去的猪最多。 买卖的过程是这样的:一个顾客前来,并打开所有他可以打开的猪圈。然后Emmy从这些猪圈里牵出固定数目的猪卖给顾客(最多只能和顾客需要数相等),并可以重新安排这些开着的猪圈中的猪。 每个猪圈可以存放任意数目的猪。 写一个程序,使得Emmy能够卖出去尽可能多的猪。
解题思路:
最大流。
从源向猪圈连容量为初始猪的数量的边。
对于每一个顾客可以开的猪圈,若该猪圈被之前的顾客打开过,则从最后打开过这个猪圈的顾客向这个顾客连容量为inf的边,否则从这个猪圈向该顾客连容量inf的边。
对于每个顾客,向汇点连容量为inf的边。
为什么这么连边呢?
首先,第一个打开猪圈的顾客拿猪是没问题的。
其次,若一个猪圈已经被一个顾客开了,那么这个顾客可以得到原来那个顾客打开的其他猪圈的猪(可以通过交换得到),更早打开的也可以通过顾客链传递过来。
C++ Code:
#include<cstdio> #include<cctype> #include<cctype> #include<cstring> #include<queue> const int S=0,T=2330,inf=0x3f3f3f3f; #include<iostream> using std::cin; using std::cout; using std::endl; int n,m,head[2333],cnt=1,pig[2333]={0},level[2333],iter[2333]; struct edge{ int to,nxt,cap; }e[400005]; 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 pig); if(bfs(),!~level[T])return flow; memcpy(iter,head,sizeof pig); while(f=dfs(S,inf))flow+=f; } } int main(){ cin>>n>>m; memset(head,-1,sizeof head); for(int i=1,p;i<=n;++i){ cin>>p; addedge(S,i,p); } for(int i=1,p;i<=m;++i){ const int id=n+i; cin>>p; for(int k;p--;){ cin>>k; if(pig[k])addedge(pig[k],id,inf);else addedge(k,id,inf); pig[k]=id; } cin>>p; addedge(id,T,p); } cout<<dinic()<<endl; return 0; }