poj 2112 最大流+二分+floyd
/* 题意:k台机器和c头牛分别在自己的点,输入为路径,c头牛要到k台机器挤奶,每台机器最多挤m头牛,求最短 的最远行走距离。 题解:最大流+二分+floyd; 题目求的是每次行走路程中每头牛行走的最远距离,因此直接在最开始的时候用floyd求出从一个点到另一个点 的最短距离,这样就保证了牛走的都是最短距离,然后根据求出的最短路径来建图,并且用二分的方法把大于值 mid的边全部去掉后,判断是否能求出最大流使得所有牛都被挤过一次,源点为0,连接每台机器,权值为m,每 头牛连接汇点k+c+1,权值为1。 */ #include <iostream> #include <cstring> #include <queue> using namespace std; #define EMAX 15000 #define VMAX 400 const int INF = 0xfffffff; int pre[VMAX]; int map[VMAX][VMAX],nmap[VMAX][VMAX]; void floyd(int n) { for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) if (INF != map[j][i]) for(int k=1; k<=n; k++) if (map[j][i] + map[i][k] < map[j][k]) map[j][k] = map[j][i] + map[i][k]; } void build(int k, int c, int m, int val) { memset(nmap,0,sizeof(nmap)); for(int i=1; i<=k; i++) nmap[0][i] = m; for(int i=1; i<=c; i++) nmap[k+i][k+c+1] = 1; for(int i=1; i<=k; i++) for(int j=1; j<=c; j++) if (map[i][k+j] <= val) nmap[i][k+j] = 1; } int flow_ek(int s, int t, int n) { queue<int> Q; int ret = 0; while (true) { memset(pre,-1,sizeof(pre)); while (!Q.empty()) Q.pop(); Q.push(s); while (!Q.empty())//BFS { int u = Q.front(); Q.pop(); for(int v=1; v<=n; v++) { if (nmap[u][v] && pre[v] == -1) { pre[v] = u; Q.push(v); } } if (pre[t] != -1)//终点的pre不为-1,表示找到一条增广路径 break; } if (pre[t] == -1)//当BFS后找不到增广路径则结束循环 break; int mw = -1; for(int v=t; v!=s; v=pre[v])//找出当前路径中的流量的最小容量 { if (mw == -1 || mw > nmap[pre[v]][v]) mw = nmap[pre[v]][v]; } for(int v=t; v!=s; v=pre[v])//修改路径的容量,求出残余网络 { nmap[pre[v]][v] -= mw; nmap[v][pre[v]] += mw;//更新逆向边 } ret += mw; } return ret; } int bin(int k, int c, int m, int n)//二分 { int left = 0, right = 40000,mid; while (left < right) { mid = (left+right)/2; build(k,c,m,mid); if (c == flow_ek(0,k+c+1,n)) right = mid; else left = mid+1; } return right; } int main(void) { int k,c,m; while (cin >> k >> c >> m) { for(int i=1; i<=k+c; i++) for(int j=1; j<=k+c; j++) { cin >> map[i][j]; if (i != j && 0==map[i][j]) map[i][j] = INF; } floyd(k+c); cout << bin(k,c,m,k+c+2) << endl; } return 0; }