【網路流】POJ3281 Dining
阿新 • • 發佈:2018-11-10
題目大意:有 N 頭牛,F 個食物,D 個飲料。N 頭牛中每頭牛隻喜歡幾個食物和飲料。每個食物和飲料只能給一頭牛。而且一頭牛必須同時獲得一個食物和一個飲料才能滿足。問至多有多少頭牛可以獲得滿足。
我們可以大致理一下對應關係:一頭牛對應幾個食物,一頭牛對應幾個飲料,而食物和飲料是沒有對應關係的。
那麼可以通過牛向食物和飲料連邊來體現對應關係。但是一個牛隻能有一個食物和一個飲料,可以把牛拆點,連一條容量為1的邊,保證一頭牛不會選多個食物或飲料。最後再跑一個最大流就行了。建圖大致如下:
【圈裡是點的編號。。飲料的我懶得畫了,刷子寫不下。食物和牛的連邊與飲料和牛的連邊我瞎畫的】
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> using namespace std; const int oo=1e7; const int maxn=1e6; const int maxm=1e6; int cnt=-1,s,t; int Head[maxn]; int Next[maxm]; int V[maxm]; int W[maxm]; int depth[maxn]; void Add(int u,int v,int w) { ++cnt; Next[cnt]=Head[u]; V[cnt]=v; W[cnt]=w; Head[u]=cnt; } void addedge(int u,int v,int w) { Add(u,v,w); Add(v,u,0); } int bfs() { memset(depth,0,sizeof(depth)); queue<int> Q; depth[s]=1; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); for(int i=Head[u];i!=-1;i=Next[i]) { if(W[i]>0&&depth[V[i]]==0) { depth[V[i]]=depth[u]+1; Q.push(V[i]); } } } return depth[t]; } int dfs(int u,int dist) { if(u==t) return dist; for(int i=Head[u];i!=-1;i=Next[i]) { if((depth[V[i]]==depth[u]+1)&&W[i]!=0) { int di=dfs(V[i],min(dist,W[i])); if(di>0) { W[i]-=di; W[i^1]+=di; return di; } } } return 0; } int dinic() { int ans=0; while(bfs()) { while(int D=dfs(s,oo)) ans+=D; } return ans; } int main() { memset(Head,-1,sizeof(Head)); memset(Next,-1,sizeof(Next)); int N,F,D; scanf("%d%d%d",&N,&F,&D); s=0,t=N+N+F+D+1; for(int i=1;i<=F;++i) addedge(s,i,1); for(int i=1;i<=N;++i) { int Fi,Di,f,d; scanf("%d%d",&Fi,&Di); for(int j=1;j<=Fi;++j) { scanf("%d",&f); addedge(f,i+F,1); } addedge(i+F,i+N+F,1); for(int j=1;j<=Di;++j) { scanf("%d",&d); addedge(i+N+F,d+F+N+N,1); } } for(int i=1;i<=D;++i) addedge(i+F+N+N,t,1); printf("%d",dinic()); }