一.原题链接:http://poj.org/problem?id=2112
二.题目大意:给出一个挤奶机与奶牛之间的图,挤奶机每天可以挤的奶牛头数是一定的。求在保证每头牛都能挤奶的情况下,求一个方案,其中奶牛要走到挤奶机前的最大路径最小。
三.思路:这题好玩,怎么想呢。
1.每头奶牛走到挤奶机的路径要尽可能小,但是奶牛走到挤奶机的路不是一步到达的,因此我们可以想到先用Floyd求出各个实体的最短路径。
2.然后,很自然的想法就是删除最大的边,求一次。再删除较大的边,再求一次。直到删到一条不能再删的边,就得到了答案。但是再深入想一下,就会觉得直接二分搜索就可以了。但是怎么求呢?
3.要让每头牛走到挤奶机面前,由于是在最大流里面看到它的,于是我们努力用最大流来想,强行最大流,自己建一个源点和汇点,将源点与每头牛之间的容量存为1,每个挤奶机与汇点之间的容量为M,牛跟它可到达的挤奶机之间距离为1。这样求一个最大流,如果求出的最大流为C,也就是奶牛数,说明可以让所有奶牛挤奶,因为所有奶牛都经过中间的挤奶点到达了汇点,而且每个挤奶点接收的流量不会超过M。
四.代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int INF = 0x3f3f3f3f, MAX_SIZE = 256; int capacity[MAX_SIZE][MAX_SIZE], graph[MAX_SIZE][MAX_SIZE], K, C, M, dist[MAX_SIZE]; void Floyd() { int i, j, k; for(k = 1; k <= K + C; k++) for(i = 1; i <= K + C; i++) for(j = 1; j <= K + C; j++) graph[i][j] = min(graph[i][j], graph[i][k] + graph[k][j]); } int maxEdge() { int i, j, res = -1; for(i = 1; i <= K + C; i++) for(j = 1; j <= K + C; j++) if(graph[i][j] < INF) res = max(res, graph[i][j]); return res; } bool BFS() { memset(dist, -1, sizeof(dist)); int i, cur; queue <int> que; que.push(0); dist[0] = 0; while(!que.empty()){ cur = que.front(); que.pop(); for(i = 0; i <= K+C+1; i++) if(-1 == dist[i] && capacity[cur][i] > 0){ que.push(i); dist[i] = dist[cur] + 1; } } if(-1 == dist[K+C+1]) return false; return true; } int DFS(int s, int minFlow) { int i, temp, save; if(s == K+C+1) return minFlow; save = minFlow; for(i = 0; i <= K+C+1; i++) if(capacity[s][i] > 0 && dist[i] == dist[s] + 1){ temp = DFS(i, min(minFlow, capacity[s][i])); capacity[s][i] -= temp; capacity[i][s] += temp; minFlow -= temp; } return save - minFlow; } void buildGraph(int maxE) { int i, j; memset(capacity, 0, sizeof(capacity)); for(i = K + 1; i <= K + C; i++) capacity[0][i] = 1; for(i = 1; i <= K; i++) capacity[i][K+C+1] = M; for(i = K + 1; i <= K + C; i++) for(j = 1; j <= K; j++) if(graph[i][j] <= maxE) capacity[i][j] = 1; } int maxFlow() { int res = 0; while(BFS()) res += DFS(0, INF); return res; } int binSearch() { int l = 1, r = maxEdge(), mid; while(l < r){ mid = (l + r)/2; buildGraph(mid); if(maxFlow() == C) r = mid; else l = mid + 1; } return r; } int main() { //freopen("in.txt", "r", stdin); int i, j; while(cin>>K>>C>>M){ for(i = 1; i <= K + C; i++) for(j = 1; j <= K + C; j++){ cin>>graph[i][j]; if(!graph[i][j]) graph[i][j] = INF; } Floyd(); cout<<binSearch(); } return 0; }