<题目链接>
题目大意:
有K台挤奶机和C头奶牛,都被视为物体,这K+C个物体之间存在路径。给出一个 (K+C)x(K+C) 的矩阵A,A[i][j]表示物体i和物体j之间的距离,有些物体之间可能没有直接通路。 每台挤奶机可以容纳m头奶牛去挤奶,且每个奶牛仅可以去往一台挤奶机。现在安排这C头奶牛去挤奶,每头奶牛会去往某个挤奶机,求出这C头奶牛去其挤奶的最长路径的最小值。
解题分析:
因为要求最长路径的最小值,所以我们很容易想到二分答案。由于数据量较小,所以我们先用floyed求出所有点之间的最短距离,然后直接二分答案,枚举最长路径的最小值,再根据枚举的值建图,源点向所有机器连一条容量为m的边,所有的牛向汇点连一条容量为1的边,并且距离<=枚举值的机器与牛连一条容量为1的边,最后求最大流,如果最大流==c,则成立。
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <algorithm> 5 #include <iostream> 6 using namespace std; 7 8 #define rep(i,s,t) for(int i=s;i<=t;i++) 9 typedef long long LL; 10 const int MX = 1050; 11 const int MXE = 4 * MX * MX; 12 const LL INFLL = 0x3f3f3f3f3f3f3f3fLL; 13 const int INF = 0x3f3f3f3f; 14 int mp[250][250]; 15 int k, c, m,maxdist; 16 struct MaxFlow { 17 struct Edge { 18 int v, nxt; 19 LL w; 20 } E[MXE]; 21 int tot, num, s, t; 22 int head[MX]; 23 void init() { 24 memset (head, -1, sizeof (head) ); 25 tot = 0; 26 } 27 void add (int u, int v, LL w) { 28 E[tot].v=v,E[tot].nxt=head[u],E[tot].w=w; 29 head[u] = tot++; 30 31 E[tot].v=u,E[tot].nxt=head[v],E[tot].w=0; 32 head[v] = tot++; 33 } 34 int d[MX], vis[MX], gap[MX]; 35 void bfs() { 36 memset (d, 0, sizeof (d) ); 37 memset (gap, 0, sizeof (gap) ); 38 memset (vis, 0, sizeof (vis) ); 39 queue<int>q; 40 q.push (t); 41 vis[t] = 1; 42 while (!q.empty() ) { 43 int u = q.front(); 44 q.pop(); 45 for (int i = head[u]; ~i; i = E[i].nxt) { 46 int v = E[i].v; 47 if (!vis[v]) { 48 d[v] = d[u] + 1; 49 gap[d[v]]++; 50 q.push (v); 51 vis[v] = 1; 52 } 53 } 54 } 55 } 56 int last[MX]; 57 LL dfs (int u, LL f) { 58 if (u == t) return f; 59 LL sap = 0; 60 for (int i = last[u]; ~i; i = E[i].nxt) { 61 int v = E[i].v; 62 if (E[i].w > 0 && d[u] == d[v] + 1) { 63 last[u] = i; 64 LL tmp = dfs (v, min (f - sap, E[i].w) ); 65 E[i].w -= tmp; 66 E[i ^ 1].w += tmp; 67 sap += tmp; 68 if (sap == f) return sap; 69 } 70 } 71 if (d[s] >= num) return sap; 72 if (! (--gap[d[u]]) ) d[s] = num; 73 ++gap[++d[u]]; 74 last[u] = head[u]; 75 return sap; 76 } 77 LL solve (int st, int ed, int n) { 78 LL flow = 0; 79 num = n;s = st;t = ed; 80 bfs(); 81 memcpy (last, head, sizeof (head) ); 82 while (d[s] < num) flow += dfs (s, INFLL); 83 return flow; 84 } 85 }Maxflow; 86 87 int MaxFlow_check(int mid) { //建图,跑最大流 88 Maxflow.init(); //初始化 89 for (int i = 1 ; i <= k ; i++) { 90 Maxflow.add(0, i, m); //源点与机器相连,容量为m 91 for (int j = k + 1 ; j <= k + c ; j++ ) 92 if (mp[i][j] <= mid) Maxflow.add(i, j, 1); //机器与牛相连,容量为1 93 } 94 for (int i = k + 1 ; i <= k + c ; i++) 95 Maxflow.add(i, k + c + 1, 1); //牛与汇点相连,容量为1 96 if ((int)(Maxflow.solve( 0, k + c + 1, k + c + 2)) == c) return 1; 97 return 0; 98 } 99 void Floyed(int n){ 100 rep(k,1,n) rep(i,1,n) rep(j,1,n){ 101 mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]); 102 maxdist=max(maxdist,mp[i][j]); //找到最大的mp[i][j],为寻找二分的上界 103 } 104 } 105 int main() { 106 while(~scanf("%d%d%d", &k, &c, &m)) { 107 for (int i = 1 ; i <= k + c ; i++) 108 for (int j = 1 ; j <= k + c ; j++) { 109 scanf("%d", &mp[i][j]); 110 if (i != j && !mp[i][j]) mp[i][j] = INF; //将0置为不可达 111 } 112 maxdist=-INF;Floyed(k+c); 113 int l = 0, r = maxdist ,ans = 0; 114 while(l <= r) { 115 int mid = (l + r) >> 1; 116 if (MaxFlow_check(mid))ans = mid,r = mid - 1; 117 else l = mid + 1; 118 } 119 printf("%d ", ans); 120 } 121 return 0; 122 }
2018-11-24