【最大流+最短路+二分】POJ-2112 Optimal Milking

来源:互联网 发布:淘宝网禅服 编辑:程序博客网 时间:2024/05/21 17:35
Optimal Milking
Time Limit: 2000MS Memory Limit: 30000K   Case Time Limit: 1000MS

Description

FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The milking machine locations are named by ID numbers 1..K; the cow locations are named by ID numbers K+1..K+C. 

Each milking point can "process" at most M (1 <= M <= 15) cows each day. 

Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine. 

Input

* Line 1: A single line with three space-separated integers: K, C, and M. 

* Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line. 

Output

A single line with a single integer that is the minimum possible total distance for the furthest walking cow. 

Sample Input

2 3 20 3 2 1 13 0 3 2 02 3 0 1 01 2 1 0 21 0 0 2 0

Sample Output

2
————————————————————清晰的分割线————————————————————
前言:建图功力是无数错误累积出来的。
思路:首先看到了最小的最大距离,又知道距离的上限,而且该距离具备单调性,因此二分答案——最大距离。
然后奶牛和奶牛、奶牛和挤奶器之间有着不同的权值,因此需要跑一遍最短路,为每头奶牛安排最佳路线。
P.S. 注意边权为0代表不可走!!
二分答案的check函数,注意到每个挤奶器有挤奶限制,奶牛总数又是不变的,因此诉诸于网络流。通过Dinic,判断最大流是否等于奶牛总数。至于边,假如某奶牛到某挤奶器之间的距离超过了最大距离,那么该边不存在。至此我认为图完整了。
因此之前我是这样建图的:(注意这是错误的)
每个挤奶器作为一个顶点,从源点向每个挤奶器之间连边,如果某奶牛可达该挤奶器,则容量++,最后是挤奶器和汇点之间连边,容量为挤奶器的限制。
这张图错在哪里呢?
注意到从汇点出发的奶牛数总和可能超过真正的奶牛数。
也就是说,从源点出发的某头奶牛,如果两个挤奶器都可以走,它就出现了分身,走了两个路线。
该数量关系没有把握好。要限制从源点出发的奶牛总数!
从源点向每头奶牛添加一条容量1的边,这样就限制了每个奶牛只可能走一条路线。然后奶牛向挤奶器连接边。
P.S. 把握好边的总数。应该是12060+。
代码如下:
/*ID: j.sure.1PROG:LANG: C++*//****************************************/#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#include <stack>#include <queue>#include <vector>#include <map>#include <string>#include <climits>#include <iostream>#define INF 0x3f3f3f3fusing namespace std;/****************************************/const int N = 333, M = 22222, MAXN = 333;int n, mac, cow, lim, G[MAXN][MAXN];struct Node {int u, v, cap;int next;}edge[M];int tot, head[N], lev[N], cur[N], q[N], s[N];int S, T;void init(){tot = 0;memset(head, -1, sizeof(head));}void add(int u, int v, int c){edge[tot].u = u; edge[tot].v = v; edge[tot].cap = c;edge[tot].next = head[u]; head[u] = tot++;}bool bfs(){int fron = 0, rear = 0;memset(lev, -1, sizeof(lev));lev[S] = 0;q[rear++] = S;while(fron < rear) {int u = q[fron%N]; fron++;for(int i = head[u]; i != -1; i = edge[i].next) {int v = edge[i].v;if(edge[i].cap && lev[v] == -1) {lev[v] = lev[u] + 1;q[rear%N] = v; rear++;if(v == T) return true;}}}return false;}void build(int maxi){init();for(int i = mac+1; i <= n; i++) {add(S, i, 1); add(i, S, 0);}for(int i = 1; i <= mac; i++) {add(i, T, lim); add(T, i, 0);}for(int i = mac+1; i <= n; i++) {for(int j = 1; j <= mac; j++) if(G[i][j] <= maxi) {add(i, j, 1); add(j, i, 0);}}}bool Dinic(int maxi){int ret = 0;build(maxi);//建图while(bfs()) {memcpy(cur, head, sizeof(cur));int u = S, top = 0;while(1) {if(u == T) {int mini = INF, loc;for(int i = 0; i < top; i++) {if(mini > edge[s[i]].cap) {mini = edge[s[i]].cap;loc = i;}}//找到路径上最小容量for(int i = 0; i < top; i++) {edge[s[i]].cap -= mini;edge[s[i]^1].cap += mini;}//修改容量ret += mini;top = loc;//回溯u = edge[s[top]].u;}int &i = cur[u];for(; i != -1; i = edge[i].next) {int v = edge[i].v;if(edge[i].cap && lev[v] == lev[u] + 1) break;//找允许弧}if(i != -1) {s[top++] = i;u = edge[i].v;}else {if(!top) break;lev[u] = -1;u = edge[s[--top]].u;}}}return ret == cow;}void Floyd(){for(int k = 1; k <= n; k++) {for(int i = 1; i <= n; i++)  {for(int j = 1; j <= n; j++)  {G[i][j] = min(G[i][j], G[i][k] + G[k][j]);}}}}int bin_S(int maxi){int low = 0, high = maxi;while(low < high) {int mid = (low + high) >> 1;if(Dinic(mid)) high = mid;else low = mid+1;}return high;}int main(){#ifdef J_Sure//freopen("000.in", "r", stdin);//freopen(".out", "w", stdout);#endifscanf("%d%d%d", &mac, &cow, &lim);n = mac + cow;S = 0; T = n+1;int x;for(int i = 1; i <= n; i++) {for(int j = 1; j <= n; j++) {scanf("%d", &x);G[i][j] = x ? x : INF;}}Floyd();int maxi = 0;for(int i = mac + 1; i <= n; i++) {for(int j = 1; j <= mac; j++) {if(G[i][j] < INF)maxi = max(maxi, G[i][j]);//奶牛距离挤奶器的最短路}}printf("%d\n", bin_S(maxi));return 0;}


0 0
原创粉丝点击