POJ-3281 Dining maximum flow, split points, super source sink

Topic link

POJ-3281

Title

N cows, m dishes, k drinks, one serving of dishes and drinks can only be given to one cow, and each cow has a fixed recipe to eat and drink only what is on it. Each cow either does not eat or drink, or eats and drinks. How many cows can eat or drink at most?

Ideas

The cow split point is split into in and out, in and out are connected, the food is connected to the cow that can eat him, the cow is connected to all drinkable beverages, the source is connected to all food, and the drink is connected to the meeting point. All side weights are 1, running the maximum flow.

Code

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
	typedef long long ll;
	const int inf=0x3f3f3f3f;
	const int maxn=10100;
	const int maxe=200010;

	int head[maxn],cnt;
	struct Edge{
    
    
		int v;
		int w;
		int next;
	}edge[maxe];

	int n,m,k,s,t;
	ll maxflow;
	int deep[maxn];//层级数,其实应该是level
	int now[maxe];//当前弧优化


	void init(){
    
    
		memset(head,-1,sizeof(head));//清空所有点对应边的联系
		cnt=0;
		maxflow=0; 
		return ;	
	}
	void add(int u,int v,int w){
    
    
  		edge[cnt].v=v;
		edge[cnt].w=w;
		edge[cnt].next=head[u];
		head[u]=cnt++;
	}

	inline bool bfs(){
    
    //在残量网络中构造分层图
    	memset(deep,0x3f,sizeof(deep));
    	queue<int>q;
    	q.push(s);deep[s] = 0;now[s] = head[s];//一些初始化
    	while(q.size()){
    
    
        	int x = q.front();q.pop();
        	for(int i=head[x];i!=-1;i=edge[i].next){
    
    
        	    int y=edge[i].v;
         	    if(edge[i].w>0&&deep[y]==inf){
    
    //没走过且剩余容量大于0
         	    	q.push(y);
        	        now[y]=head[y];//先初始化,暂时都一样
         	       	deep[y]=deep[x]+1;
        	        if(y==t)	return 1;//找到了
				}
        	}
    	}
    	return 0;
	}

//flow是整条增广路对最大流的贡献,rest是当前最小剩余容量,用rest去更新flow
	ll dfs(int x,int flow){
    
    //在当前分层图上增广
    	if(x==t)	return flow;
    	ll ans = 0,k,i;
    	for(i=now[x];i!=-1&&flow;i=edge[i].next){
    
    
        	now[x]=i;//当前弧优化(避免重复遍历从x出发的不可拓展的边)
        	int y=edge[i].v;
        	if(edge[i].w>0&&(deep[y]==deep[x]+1)){
    
    //必须是下一层并且剩余容量大于0
        	    k=dfs(y,min(flow,edge[i].w));//取最小
         		if(!k)	deep[y]=inf;//剪枝,去掉增广完毕的点
            	edge[i].w-=k;//回溯时更新
            	edge[i^1].w+=k;//成对变换
            	ans+=k;
            	flow-=k;
        	}
    	}
    	return ans;
	}	

	void dinic(){
    
    
    	while(bfs())
    	    maxflow+=dfs(s,inf);
	}

	int main(){
    
    	
		IOS
		//1--n 牛in,n+1--2n 牛out,2n+1--2n+m 食物, 2n+m+1-2n+m+k 饮料, 2n+m+k+1源点,2n+m+k+2 汇点。 
		cin>>n>>m>>k;
    	init();
    	s=2*n+m+k+1,t=s+1;
	    for(int i=1;i<=n;i++){
    
    
    		int a,b,x;
    		cin>>a>>b;
    		while(a--){
    
    
    			cin>>x;
    			x+=2*n;
    			add(x,i,1),add(i,x,0);
			}
    		while(b--){
    
    
    			cin>>x;
    			x+=2*n+m;
    			add(i+n,x,1),add(x,i+n,0);
			}
		}
		for(int i=1;i<=n;i++)
			add(i,i+n,1),add(i+n,i,0);
		for(int i=1;i<=m;i++)
			add(s,2*n+i,1),add(2*n+i,s,0);
		for(int i=1;i<=k;i++)
			add(2*n+m+i,t,1),add(t,2*n+m+i,0);
    	dinic();
    	cout<<maxflow<<endl;
    	return 0;
	}

Guess you like

Origin blog.csdn.net/TheSunspot/article/details/108129776