2391:Ombrophobic Bovines

問題文
http://poj.org/problem?id=2391

n頭の牛とm個のフィールドがある。
フィールドにはそれぞれ小屋があり、入れる牛の数も決まっている。
また、フィールド同士は辺でつながっている。
辺には牛が通れる数の制限はない。
全ての牛が小屋に入ることを考える。
最後に小屋に入る牛の小屋に入るまでの時間を最小化せよ。





















二分探索+最大流。
牛が通れる数を容量とした2部グラフをつくる。
このとき、二分探索で求めたい時間を決め打ちして、その時間より大きい辺は使わないようにする。
このグラフでの最大流が牛の数と一致していれば、その時間ですべての牛を小屋に入れることができる。

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstdio>
#include <cstring>
#define MAX_V 405
#define INF (1LL<<60)

using namespace std;

typedef long long ll;
typedef pair<ll,ll> pll;

struct edge{ll to,cap,rev;};

vector<edge>G[MAX_V];

inline void add_edge(ll from,ll to,ll cap){
	G[from].push_back((edge){to,cap,G[to].size()});
	G[to].push_back((edge){from,0,G[from].size()-1});
}

ll level[MAX_V],iter[MAX_V];

inline ll bfs(ll s){
	memset(level, -1, sizeof(level));
	queue<ll>que;
	level[s]=0;
	que.push(s);
	while(!que.empty()){
		ll v=que.front();
		que.pop();
		int sz=G[v].size();
		for(int i=0;i<sz;i++){
			edge &e=G[v][i];
			if(e.cap>0 && level[e.to]<0){
				level[e.to]=level[v]+1;
				que.push(e.to);
			}
		}
	}
}

inline ll dfs(ll v,ll t,ll f){
	if(v==t)return f;
	int sz=G[v].size();
	for(ll &i=iter[v];i<sz;i++){
		edge &e=G[v][i];
		if(e.cap>0 && level[v]<level[e.to]){
			ll d=dfs(e.to,t,min(e.cap,f));
			if(d>0){
				e.cap-=d;
				G[e.to][e.rev].cap+=d;
				return d;
			}
		}
	}
	return 0;
}

inline ll max_flow(ll s,ll t,ll lim){
	ll flow=0;
	for(;;){
		bfs(s);
		if(level[t]<0)return flow;
		memset(iter, 0, sizeof(iter));
		ll f;
		while((f=dfs(s,t,INF))>0)flow+=f;
	}
}

ll wf[MAX_V][MAX_V];

int main(void){

	ll n,m,sum=0;
	cin >> n >> m;

	vector<pll>v(n);
	for(int i=0;i<n;i++){
		scanf("%d %d",&v[i].first,&v[i].second);
		sum+=v[i].first;
	}

	fill(wf[0],wf[MAX_V],INF);
	for(int i=0;i<MAX_V;i++)wf[i][i]=0;

	ll s=2*n,t=s+1;
	vector<pll>sp(m);
	vector<ll>p(m);
	for(int i=0;i<m;i++){
		scanf("%d %d %d",&sp[i].first,&sp[i].second,&p[i]);
		sp[i].first--,sp[i].second--;
		ll tmp=min(wf[sp[i].first][sp[i].second],p[i]);
		wf[sp[i].first][sp[i].second]=tmp;
		wf[sp[i].second][sp[i].first]=tmp;
	}

	for(int k=0;k<n;k++){
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				wf[i][j]=min(wf[i][j],wf[i][k]+wf[k][j]);
			}
		}
	}

	ll l=0,r=INF;
	while(r-l>1){

		ll mid=(l+r)/2;

		for(int i=0;i<=t;i++)G[i].clear();

		for(int i=0;i<n;i++){
			add_edge(s,i,v[i].first);
			add_edge(i+n,t,v[i].second);

			for(int j=0;j<n;j++){
				if(mid>=wf[i][j])add_edge(i,j+n,sum);
			}
		}

		if(max_flow(s,t,mid)==sum)r=mid;
		else l=mid;
	}

	if(r==INF)cout << -1 << endl;
	else cout << r << endl;

	return 0;
}