Dining POJ - 3281 (網路流)
阿新 • • 發佈:2018-10-31
題意:農夫約翰為他的N頭牛準備了F種食物和D種飲料。每頭牛都有各自喜歡的食物和飲料,而每種食物或飲料只能分配給一頭牛。最多能有多少頭牛同時得到自己喜歡的食物和飲料?
題解:如果只是分配食物的話,那麼用二分圖最大匹配就好了,但遇到這種情況需要同時給一頭牛分配所喜歡的食物和飲料的情況,就不能很好的處理了,可以將食物和飲料所對應的兩個匹配通過下面這種方法匹配起來。
圖的頂點在食物對應的匹配中的食物和牛,飲料對應的匹配中的飲料和牛之外,還有一個源點s和一個匯點t。
在兩個匹配相同的牛之間連一條邊,在s和所有食物,t和所有飲料之間連一條邊。
邊的方向為s->食物->牛->牛->飲料->t,容量全都為1。
這個圖中的每一條s-t路徑都對應一個牛的食物和飲料的分配方案。我們把食物所對應的牛和飲料所對應的牛拆成兩個頂點,之間連一條容量為1的邊,就保證了一頭牛不會被分配多組食物和飲料。只要計算該圖中的最大流,問題就解決了。
附上程式碼:
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int MAX_N=150; const int MAX_D=150; const int MAX_F=150; const int MAX_V=1000; const int INF=0x3f3f3f3f; int N,F,D; int likeF[MAX_N][MAX_F]; int likeD[MAX_N][MAX_D]; struct edge{ int to,cap,rev; edge(int _to,int _cap,int _rev):to(_to),cap(_cap),rev(_rev){} }; vector<edge>G[MAX_V]; int level[MAX_V]; int iter[MAX_V]; void add_edge(int from,int to,int cap) { G[from].push_back(edge(to,cap,G[to].size())); G[to].push_back(edge(from,0,G[from].size()-1)); } void bfs(int s) { memset(level,-1,sizeof(level)); queue<int>que; level[s]=0; que.push(s); while(!que.empty()){ int v=que.front();que.pop(); for(int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[e.to]<0){ level[e.to]=level[v]+1; que.push(e.to); } } } } int dfs(int v,int t,int f) { if(v==t){ return f; } for(int &i=iter[v];i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&level[v]<level[e.to]){ int d=dfs(e.to,t,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } } return 0; } int max_flow(int s,int t) { int flow=0; for(;;){ bfs(s); if(level[t]<0){ return flow; } memset(iter,0,sizeof(iter)); int f; while((f=dfs(s,t,INF))>0){ flow+=f; } } } void solve() { int s=N*2+F+D,t=s+1; for(int i=0;i<F;i++){ add_edge(s,N*2+i,1); } for(int i=0;i<D;i++){ add_edge(N*2+F+i,t,1); } for(int i=0;i<N;i++){ add_edge(i,N+i,1); for(int j=0;j<F;j++){ if(likeF[i][j]){ add_edge(N*2+j,i,1); } } for(int j=0;j<D;j++){ if(likeD[i][j]){ add_edge(N+i,N*2+F+j,1); } } } printf("%d\n",max_flow(s,t)); } int main() { scanf("%d%d%d",&N,&F,&D); int cntf,cntd; for(int i=0;i<N;i++){ scanf("%d%d",&cntf,&cntd); int temp; for(int j=0;j<cntf;j++){ scanf("%d",&temp); temp--; likeF[i][temp]=1; } for(int j=0;j<cntd;j++){ scanf("%d",&temp); temp--; likeD[i][temp]=1; } } solve(); return 0; }