1. 程式人生 > >floyd +二分答案+最大流 poj2112

floyd +二分答案+最大流 poj2112

http://poj.org/problem?id=2112
題意:
有n個機器,有c個奶牛,每個機器能夠最多接受m個奶牛。給出一個距離(n+c)*(n+c) 的距離矩陣,問要讓每一個奶牛都能走到一個機器,求這種情況下走的最遠的奶牛的最小的距離。
思路:
很容易看出這是一個最大值最小化的問題。
先進行floyd,跑出最短路。進行二分答案,對於這個走的最遠的距離,如果奶牛到某一個機器的距離小於等於這個距離,那麼就可以在這個奶牛和機器之間連一條邊,容量為1。然後對於源點s到每個奶牛連一條邊,容量為1。對於每個機器連一條邊到匯點t,容量為m。
最後這個最大流量就是能夠有幾個奶牛走到機器上。如果所有奶牛都能走到,那麼就縮短這個距離,繼續操作。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define M 300
typedef struct edge
{
    int to,cap,rev;
};
const int INF = 0x3f3f3f3f;
vector<edge> G[M];
int dis[M][M];
int level[M],iter[M];
int
n,c,m; int s,t; void floyd() { for(int k = 1; k <= n+c;k++) { for(int i = 1; i <= n+c;i++) { for(int j = 1; j <= n+c;j++) { dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]); } } } } void add_edge(int u,int
v,int cap) { G[u].push_back(edge{v,cap,G[v].size()}); G[v].push_back(edge{u,0,G[u].size()-1}); } void build(int dd) { for(int i = 0;i <= n+c;i++) G[i].clear(); for(int i = n+1;i <= n+c;i++) { for(int j = 1;j <= n;j++) { if(dis[i][j] <= dd) add_edge(i,j,1); } } for(int i = 1; i <= n;i++) add_edge(i,t,m); for(int i = n+1; i <= n+c;i++) add_edge(s,i,1); } void bfs(int s) { memset(level,-1,sizeof(level)); queue<int> q; level[s] = 0; q.push(s); while(!q.empty()) { int v = q.front(); q.pop(); for(int i = 0;i < G[v].size();i++) { edge& e = G[v][i]; if(e.cap > 0 && level[e.to] < 0) { level[e.to] = level[v] + 1; q.push(e.to); } } } } int dfs(int u,int t,int f) { if(u == t) return f; for(int& i = iter[u];i < G[u].size();i++) { edge& e = G[u][i]; if(e.cap > 0 && level[u] < level[e.to]) { int d = dfs(e.to,t,min(f,e.cap)); if(d > 0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } int max_flow() { int flow = 0; for(;;) { bfs(s); memset(iter,0,sizeof(iter)); if(level[t] < 0 ) return flow; int f ; while((f = dfs(s,t,INF)) > 0 ) flow += f; } } int main() { while(scanf("%d %d %d",&n,&c,&m) == 3) { s = 0; t = n+c+1; for(int i = 1; i <= n+c;i++) { for(int j = 1; j <= n+c;j++) { scanf("%d",&dis[i][j]); if(dis[i][j] == 0 && i != j) dis[i][j] = INF; } } floyd(); /*for(int i = 1; i <= n+c;i++) { for(int j = 1; j <= n+c;j++) printf("%d ",dis[i][j]); printf("\n"); }*/ int l = 0, r = INF; while(r - l > 1) { int mid = (l+r)/2; build(mid); int flow = max_flow(); if(flow == c) r = mid; else l = mid; } printf("%d\n",r); } return 0; }