Dining(最大流+拆點)

http://poj.org/problem?id=3281

題意:牛隻能吃一種食物和喝一個飲料,牛喜歡多種食物和飲料,現在每種食物飲料都只有一個,問你一共有多少牛可以吃上喝上

題解:難在建圖

           我想的是源點->食物->牛->飲料->匯點,容量都爲1 ,但這樣搞會出現一頭牛吃了好幾種食物(會有多種食物指向一頭牛)再流向匯點所以不行,

          這時候拆點!!(見到網絡流題一定要想拆點),把牛點拆成牛->牛(容量爲1)這樣從牛往下面流的時候,因爲容量限制1,你只能流1了,這樣就解決了上面的問題,最後跑到匯點的值就是該網絡的最大流了(多少牛吃上喝上)。

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<queue> 
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000; 
typedef long long LL;
const int N = 20005;
const int INF = 0x3f3f3f3f;
bool vis[N];
struct Edge{
    int to, cap, flow, next;
}edge[N*50];
int n, m, cnt;//n是點 m是邊 cnt是加邊操作後的邊 
int head[N];//鄰接表 
int dis[N];//分層 等級 
int  cur[N];//弧優化 
void add(int u, int v, int w){
    edge[cnt] = (struct Edge){v, w, 0, head[u]};
    head[u] = cnt++;
    edge[cnt] = (struct Edge){u, 0, 0, head[v]};
    head[v] = cnt++;
}
 
bool bfs(int start, int endd){//分層 
    memset(dis, -1, sizeof(dis));
    memset(vis, false, sizeof(vis));
    queue<int>que;
    dis[start] = 0;
    vis[start] = true;
    que.push(start);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = head[u]; i != -1; i = edge[i].next){
            Edge E = edge[i];
            if(!vis[E.to] && E.flow<E.cap){
                dis[E.to] = dis[u]+1;
                vis[E.to] = true;
                if(E.to == endd) return true;
                que.push(E.to);
            }
        }
    }
    return false;
}
 
int dfs(int x, int res, int endd){ //增廣 
	if(x == endd || res == 0) return res;
	int flow = 0, f;
	for(int& i = cur[x]; i != -1; i = edge[i].next){
		Edge E = edge[i];
		if(dis[E.to] == dis[x]+1){
		    f = dfs(E.to, min(res, E.cap-E.flow), endd);
            if(f>0){
                edge[i].flow += f;
                edge[i^1].flow -= f;
                flow += f;
                res -= f;
                if(res == 0) break;
            }
		}
	}
	return flow;
}

int max_flow(int start, int endd){
    int flow = 0;
    while(bfs(start, endd)){
        memcpy(cur, head, sizeof(head));//初始化弧優化數組 
        flow += dfs(start, INF, endd);
    }
    return flow;
}
 
void init(){//初始化 
    cnt = 0;
    memset(head, -1, sizeof(head));
}
int main(){
    init();
   int n,f,d;
   cin>>n>>f>>d;
   int sp=0;
   int tp=2*n+f+d+1;
   for(int i=1;i<=f;i++){
   	    add(sp,i,1);
   }
   for(int i=1;i<=n;i++){
   	   	int x,y;
   	   	cin>>x>>y;
   	   	for(int j=1;j<=x;j++){
   	   		int xx;
   	   		cin>>xx;
   	   	    add(xx,f+i*2-1,1);	//食物和牛 
		}
		add(f+i*2-1,f+i*2,1);//牛和牛  拆點 
		for(int k=1;k<=y;k++){
			int yy;
			cin>>yy;
			add(f+i*2,f+2*n+yy,1);//牛和飲料 
		}
   }
   for(int i=1;i<=d;i++){
   	    add(f+2*n+i,tp,1);//飲料喝匯點 
   }
   int  ans=max_flow(sp,tp);
   cout<<ans<<endl;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章