POJ-3281 Flujo máximo de comedor, puntos de división, súper fregadero de fuente

Enlace de tema

POJ-3281

Título

N vacas, m platos, k bebidas, una ración de platos y bebidas sólo se le puede dar a una vaca, y cada vaca tiene una receta fija para comer y beber sólo lo que contiene. Cada vaca no come ni bebe, o come y bebe ¿Cuántas vacas pueden comer o beber como máximo?

Ideas

El punto de división de la vaca se divide en adentro y afuera, adentro y afuera están conectados, la comida está conectada a la vaca que puede comerla, la vaca está conectada a todas las bebidas bebibles, la fuente está conectada a toda la comida y la bebida está conectada al punto de encuentro. Todos los pesos laterales son 1, ejecutando el flujo máximo.

Código

#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;
	}

Supongo que te gusta

Origin blog.csdn.net/TheSunspot/article/details/108129776
Recomendado
Clasificación