網路流拆點法和分配結點和超級源點匯點的應用

minato_yukina發表於2020-12-08

有F種食物和D種飲料,每種食物或飲料只能供一頭牛享用,且每頭牛隻享用一種食物和一種飲料。現在有n頭牛,每頭牛都有自己喜歡的食物種類列表和飲料種類列表,問最多能使幾頭牛同時享用到自己喜歡的食物和飲料。(1 <= f <= 100, 1 <= d <= 100, 1 <= n <= 100)

一種顯然的想法是所有食物連源點,所有飲料連線匯點,然後讓牛為中間結點,跑一次最大流. 但是這樣會出現一個牛用了多個食物和飲料的情況。

這種情況下我們把牛拆成兩部分(i,N+i)i部分與食物連線,N+i部分與飲料連線,然後兩部分自己連線(流量為1)。這樣跑出來的網路流,保證了每個牛隻有一種分配方案.注意體會飲料,食物,牛之間的編號方法.還有源點匯點的編號.

因為要保證各個點之間不會出現重複的現象,現規定0-N-1是第一部分牛的編號. N-2N-1部分是第二部分牛. 2*N-2*N+f是食物部分 2*N+f-2*N+f+d是飲料部分,不放心的中間自己加點常數啥的

最後源點s=2*n+f+d 匯點t=s+1;

程式碼部分:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#define maxn 500
#define INF 10000000
using namespace std;
struct Edge{
	int from,to,cap,flow;
};
struct Dinic{
	int n,m,s,t;
	vector<Edge> edges;vector<int> G[maxn];
	bool vis[maxn];int d[maxn],cur[maxn];
	void init(int n){
		for(int i=0;i<n;i++) G[i].clear();
		edges.clear();
	}
	void addedge(int from,int to,int cap){
		edges.push_back((Edge){from,to,cap,0});
		edges.push_back((Edge){to,from,0,0});
		m=edges.size();G[from].push_back(m-2);G[to].push_back(m-1);
	}
	bool bfs(){
		memset(vis,0,sizeof(vis));
		queue<int> Q;Q.push(s);vis[s]=1;d[s]=0;
		while(!Q.empty()){
			int x=Q.front();Q.pop();
			for(int i=0;i<G[x].size();i++){
				Edge &e=edges[G[x][i]];
				if(!vis[e.to]&&e.cap>e.flow){
					vis[e.to]=1;
					d[e.to]=d[x]+1;
					Q.push(e.to);
				}
			}
		} return vis[t];
	}
	int dfs(int x,int a){
		if(x==t||a==0) return a;
		int flow=0,f;
		for(int &i=cur[x];i<G[x].size();i++){
			Edge &e=edges[G[x][i]];
			if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
				e.flow+=f;edges[G[x][i]^1].flow-=f;
				a-=f;flow+=f;
				if(a==0) break;
			}
		} return flow;
	}
	int Max_flow(int s,int t){
		this->s=s;this->t=t;
		int flow=0;
		while(bfs()){
			memset(cur,0,sizeof(cur));flow+=dfs(s,INF);
		} return flow;
	}
};int lf[105][105],ld[105][105];
int main(){ int N,F,D,i,j,k,food,drink,temp;cin>>N>>F>>D;
Dinic dd;memset(lf,0,sizeof(lf));memset(ld,0,sizeof(ld));
for(i=0;i<N;i++){
	scanf("%d%d",&food,&drink);
	while(food--){ scanf("%d",&temp);lf[i][temp-1]=1;
	}
	while(drink--){ scanf("%d",&temp);ld[i][temp-1]=1;
	}
} //foodnumber=2*N+i drinknumber=2*N+f+i
int s=2*N+F+D+20; int t=s+1;
for(i=0;i<F;i++){
	dd.addedge(s,2*N+i,1);   // link food to s
}
for(i=0;i<D;i++){
	dd.addedge(2*N+i+F,t,1); //t to drink
}
for(i=0;i<N;i++){
	dd.addedge(i,N+i,1);              //cow to cow
	for(j=0;j<F;j++) {
		if(lf[i][j]) dd.addedge(2*N+j,i,1);  // food to cow
	}
	for(j=0;j<D;j++){
		if(ld[i][j]) dd.addedge(N+i,2*N+F+j,1); //cow to drink
	}
}
printf("%d\n",dd.Max_flow(s,t));	
return 0;}

 

相關文章