POJ-2391 Ombrophobic Bovines 网络流-拆点构图
题意:有F快草地,每块草地上有若干奶牛也有避雨点,每个避雨点只能够容纳一定量的奶牛。草地之间有边。现在问所有牛全部到达避雨点的时间是多少?
解法:这题和POJ-2112非常相似,做法也差不多,folyd处理之后二分枚举答案。该题的构图稍微难一点,需要考虑到一个流量的控制问题,即当某一点多余的流量流出去后必须在下一个点停止住。自己是把一个点拆成了3个点进行控制,后面学习了别人拆成两个点也能完成。
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const long long INF = 0x3f3f3f3f3f3f3f3fLL; int F, P, sum; const int SS = 402, TT = 403; struct Edge { int v, c, next; }; Edge e[200000]; LL mp[205][205]; int in[405], out[405]; int idx, head[405], lv[405]; int front, tail, que[405]; void floyd() { for (int k = 1;k <= F; ++k) { for (int i = 1; i <= F; ++i) { if (mp[i][k] == INF || i == k) continue; for (int j = 1; j <= F; ++j) { if (mp[k][j] == INF || j == k) continue; mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); } } } } void insert(int a, int b, int c) { e[idx].v = b, e[idx].c = c; e[idx].next = head[a]; head[a] = idx++; } void build(LL threshold) { idx = 0; memset(head, 0xff, sizeof (head)); for (int i = 1; i <= F; ++i) { if (in[i]) { insert(SS, i, in[i]), insert(i, SS, 0); } insert(i, 200+i, 1000000), insert(200+i, i, 0); if (out[i]) { insert(200+i, TT, out[i]), insert(TT, 200+i, 0); } for (int j = 1; j <= F; ++j) { if (mp[i][j] <= threshold) { insert(i, j+200, 1000000); insert(j+200, i, 0); } } } } bool bfs() { memset(lv, 0xff, sizeof (lv)); front = tail = lv[SS] = 0; que[tail++] = SS; while (front < tail) { int u = que[front++]; for (int i = head[u]; i != -1; i = e[i].next) { if (!(~lv[e[i].v]) && e[i].c) { lv[e[i].v] = lv[u] + 1; if (e[i].v == TT) return true; que[tail++] = e[i].v; } } } return false; } int dfs(int u, int sup) { if (u == TT) return sup; int tf = 0, f; for (int i = head[u]; i != -1; i = e[i].next) { if (lv[u]+1==lv[e[i].v] && e[i].c && (f=dfs(e[i].v, min(e[i].c, sup-tf)))) { tf += f; e[i].c -= f, e[i^1].c += f; if (tf == sup) return sup; } } if (!tf) lv[u] = -1; return tf; } int dinic() { int ret = 0; while (bfs()) { ret += dfs(SS, 1000000); } return ret; } LL bsearch(LL l, LL r) { LL ret = -1, mid; while (l <= r) { mid = (l + r) >> 1; if (build(mid), dinic() == sum) { r = mid - 1; ret = mid; } else { l = mid + 1; } } return ret; } int main() { int a, b; LL c; while (scanf("%d %d", &F, &P) != EOF) { sum = 0; memset(mp, 0x3f, sizeof (mp)); for (int i = 1; i <= F; ++i) { scanf("%d %d", &in[i], &out[i]); sum += in[i]; } for (int i = 1; i <= P; ++i) { scanf("%d %d %I64d", &a, &b, &c); if (c < mp[a][b]) { mp[a][b] = mp[b][a] = c; } } floyd(); printf("%I64d\n", bsearch(0, INF-1));
// 不减去1,那么-1将会输出INF...... } return 0; }