The Perfect Stall(最大流+建图)

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

题意:n头牛 m个谷仓,一头牛只愿意去 一个固定的谷仓产奶(牛喜欢好几个谷仓),问有多少头牛可以去产内

题解:最大流写,想着尽量占满谷仓构建模型,建立超级源点 超级汇点,源点连接所有牛 ,  牛连接喜欢的谷仓,  谷仓连接汇点 ,然后跑就行了

二分图也可以写,我不会

#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<stdlib.h>
#include<queue> 
using namespace std;
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(){

	int na,nb;
	while(cin>>na>>nb){
	init();
	int sp=0;//超级源点 
	int tp=na+nb+1;//超级汇点 
	for(int i=1;i<=na;i++){
		add(sp,i,1);//源点与 牛连边 
		int k;
		cin>>k;
		for(int j=1;j<=k;j++){
			int x;
			cin>>x;
			add(i,na+x,1);//牛与谷仓连边 
		}
	}
	for(int j=1;j<=nb;j++){
		add(na+j,tp,1);//谷仓与汇点连边 
	}	    
	int ans=max_flow(sp,tp);
	cout<<ans<<endl;
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/gml1999/article/details/89763122