Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 13897 | Accepted: 5018 | |
Case Time Limit: 1000MS |
Description
Input
Output
Sample Input
2 3 2 0 3 2 1 1 3 0 3 2 0 2 3 0 1 0 1 2 1 0 2 1 0 0 2 0
Sample Output
2
上面图片有详细的题意和解析,来自图论算法理论,实现及应用这本书。
先用floyd求解任意两点之间的最短距离,再构建网络,将牛与源点相连容量为1(则从原点出去的中流量为C),将挤奶器与汇点相连容量为m。然后用dinic算法求最大流,二分枚举答案,将牛与挤奶器之间的距离小于枚举值得边 加入网络,大于枚举值得边去掉。找到可以使汇点的流入量为C的且符合条件的最小值就是答案。
#include <cstdio> #include <cstring> #include <iostream> #include <vector> #include <queue> #include <algorithm> #define maxn 1100 #define maxm 550000 #define INF 1000000 using namespace std; int dist[maxn], vis[maxn]; int head[maxn], cur[maxn], cnt; int map[maxn][maxn]; struct node{ int u, v, cap, flow, next; }; node edge[maxm]; int K, C, M, n; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void add(int u, int v, int w){ edge[cnt] = {u, v, w, 0, head[u]}; head[u] = cnt++; edge[cnt] = {v, u, 0, 0, head[v]}; head[v] = cnt++; } void getmap(int min_max){ int i, j; for(i = K + 1; i <= n; ++i) add(0, i, 1); for(i = 1; i <= K; ++i) add(i, n + 1, M); for(i = K + 1; i <= n; ++i) for(j = 1; j <= K; ++j) if(map[i][j] <= min_max) add(i, j, 1); } bool BFS(int st, int ed){ queue<int>q; memset(vis, 0, sizeof(vis)); memset(dist, -1, sizeof(dist)); q.push(st); vis[st] = 1; dist[st] = 0; while(!q.empty()){ int u = q.front(); q.pop(); for(int i = head[u]; i != -1; i = edge[i].next){ node E = edge[i]; if(!vis[E.v] && E.cap > E.flow){ vis[E.v] = 1; dist[E.v] = dist[u] + 1; if(E.v == ed) return true; q.push(E.v); } } } return false; } int DFS(int x, int ed, int a){ if(a == 0 || x == ed) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i =edge[i].next){ node &E = edge[i]; if(dist[E.v] == dist[x] + 1 && (f = DFS(E.v, ed, min(a, E.cap - E.flow))) > 0){ E.flow += f; edge[i ^ 1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int maxflow (int st, int ed){ int flowsum = 0; while(BFS(st, ed)){ memcpy(cur, head, sizeof(head)); flowsum += DFS(st, ed, INF); } return flowsum; } int main (){ while(scanf("%d%d%d", &K,&C,&M) != EOF){ n = C + K; int i, j , k; for(i = 1; i <= n; ++i) for(j = 1; j <= n; ++j){ scanf("%d", &map[i][j]); if(map[i][j] == 0) map[i][j] = INF; } for(k = 1; k <= n; ++k) for(i = 1; i <= n; ++i) if(map[i][k] != INF){ for(j = 1; j <= n; ++j) map[i][j] = min(map[i][k] + map[k][j], map[i][j]); } int L = 0, R = 60000, mid, ans; while( R > L){ mid = (L + R) / 2; ans = 0; init(); getmap(mid); ans = maxflow(0, n + 1); if(ans >= C) R = mid; else L = mid + 1; } printf("%d\n", R); } return 0; }