[BZOJ1280]Emmy賣豬pigs
阿新 • • 發佈:2018-07-10
通過 style 最大 程序 pop 初始 code 會有 void
題目大意:
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; }
[BZOJ1280]Emmy賣豬pigs