ACM/ICPC 之 网络流-拆点构图(POJ2391)
需要直接到达,因此源点经过三条边后必须要达到汇点,但为了保证网络流的正确性(路径可反悔),因此不可限制层次网络的最高层次为3,最好的方法既是让所有点拆分成两个点,一个点从汇点进入,一个点通向汇点,任意两点的路径则标注为最短路径。
//Dinic算法-拆点构图 //Time:625Ms Memory:2108K #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> using namespace std; #define MAX 405 #define INF 0x3f3f3f3f #define LL long long int n, m; int s, t; int cow[MAX], hide[MAX]; LL d[MAX][MAX]; int res[MAX][MAX]; int lev[MAX]; void build_map(LL limit) //拆点构图 { memset(res, 0, sizeof(res)); for (int i = 1; i <= n; i++) { res[s][i] = cow[i]; res[i + n][t] = hide[i]; } for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (d[i][j] <= limit) res[i][j + n] = INF; } bool bfs() //构建层次网络 { memset(lev, -1, sizeof(lev)); queue<int> q; q.push(s); lev[s] = 0; while (!q.empty() && lev[t] == -1) { int cur = q.front(); q.pop(); for (int i = 1; i <= t; i++) { if (lev[i] == -1 && res[cur][i]) { lev[i] = lev[cur] + 1; q.push(i); } } } return lev[t] != -1; } int dfs(int x, int sum) //增广并更新 { if (x == t || sum == 0) return sum; int src = sum; for (int i = 1; i <= t; i++) { if (lev[i] == lev[x] + 1 && res[x][i]) { int tmp = dfs(i, min(sum, res[x][i])); res[x][i] -= tmp; res[i][x] += tmp; sum -= tmp; } } return src - sum; } int Dinic() { int maxFlow = 0; while (bfs()) maxFlow += dfs(0, INF); return maxFlow; } int main() { //freopen("in.txt", "r", stdin); memset(d, INF, sizeof(d)); scanf("%d%d", &n, &m); s = 0; t = 2 * n + 1; int cows = 0; //总牛数 for (int i = 1; i <= n; i++) { scanf("%d%d", &cow[i], &hide[i]); cows += cow[i]; } for (int i = 1; i <= m; i++) { int u, v; LL w; scanf("%d%d%lld", &u, &v, &w); d[u][v] = d[v][u] = min(w, d[u][v]); } //Floyd for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) { d[0][i] = d[i][t] = 0; if (d[i][k] != d[0][0]) { for (int j = 1; j <= n; j++) { if (i != j) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); else d[i][j] = 0; } } } LL l = 0, r = 200LL * 1000000000; int last; while (l < r) { LL mid = (l + r) / 2; build_map(mid); last = Dinic(); last == cows ? r = mid : l = mid + 1; } if (r != 200LL * 1000000000) printf("%lld\n", r); else printf("-1\n"); return 0; }
他坐在湖边,望向天空,她坐在对岸,盯着湖面