POJ 2175 Evacuation Plan 费用流消圈 好题
题意:给出n栋房子位置和每栋房子里面的人数,m个避难所位置和每个避难所可容纳人数。然后给出一个方案,判断该方案是否最优,如果不是求出一个更优的方案。
思路:很容易想到用最小费用流求出最优时间,在与原方案花费时间对比判断原方案是否最优。但是这种方法会超时的。 放弃该思路。
看看题目没要求要最优解,而是得到一个更优的解,那么如果在原图中能够找到一个总费用为负的回路的话,那就该解不是最优解,把该负环消去,更新流量,得到优化后的解。
具体操作:在SPFA中,一个点入队次数大于顶点数时就可以判断有负圈存在了,但这时刚刚入队的这个点却未必是负圈上的,
如数据
1 3
0 0 4
1 0 6
1 1 6
1 2 6
0 2 2
我们用spfa找到了其中一个负环:花费:-4 -> 2 -> 0 -> 0 -> -4,最后一个入栈的点是3,不在该负环中
但我们可以记录下来每个点被更新的前一个点,沿这个路径不停地回溯去找,直到发现找到的这个点在之间已经遇到过了,那么找到的这个点就一定是某个负圈上的点了。最后以这个点为基础,回溯找到整个负圈并更新流量即可。
费用流做个几题,这题建边不是问题,关键是想法。
View Code
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define maxn 222 #define maxm maxn * maxn #define inf 1000000000 int min(int a, int b) { return a < b ? a : b; } struct E { int u, v, next, c, w; }edge[maxm<<3]; int head[maxn], tot; int n, m; int S, T; void add(int s, int t, int c, int cc, int w) { edge[tot].u = s; edge[tot].v = t; edge[tot].c = c; edge[tot].w = w; edge[tot].next = head[s]; head[s] = tot++; edge[tot].u = t; edge[tot].v = s; edge[tot].c = cc; edge[tot].w = -w; edge[tot].next = head[t]; head[t] = tot++; } void init() { tot = 0; memset(head, -1, sizeof(head)); } int pre[maxn]; int dis[maxn]; int in[maxn]; bool vis[maxn]; int spfa(int s, int n) { int i, u, v; for(i = 0; i <= n; i++) dis[i] = inf, pre[i] = -1, vis[i] = 0, in[i] = 0; queue<int> q; dis[s] = 0; vis[s] = 1; in[s]++; q.push(s); while(!q.empty()) { u = q.front(); q.pop(); vis[u] = 0; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c && dis[v] > dis[u] + edge[i].w) { dis[v] = dis[u] + edge[i].w; pre[v] = i; if(!vis[v]) { vis[v] = 1; q.push(v); in[v]++; if(in[v] >= n) return v; } } } } return -1; } int ax[maxn], ay[maxn], ac[maxn], bx[maxn], by[maxn], bc[maxn]; int b[maxn]; int Dis(int i, int j) { return abs(ax[i] - bx[j]) + abs(ay[i] - by[j]) + 1; } void update(int p) // 更新费用流 { int u = pre[p], i; int aug; aug = min(aug, edge[u].c); for(i = pre[edge[u].u]; i != u; i = pre[edge[i].u]) aug = min(aug, edge[i].c); edge[u].c -= aug; edge[u^1].c += aug; for(i = pre[edge[u].u]; i != u; i = pre[edge[i].u]) { edge[i].c -= aug; edge[i^1].c += aug; } } void solve() { int p = spfa(T, T); int i, j; if(p == -1) { printf("OPTIMAL\n"); return; } printf("SUBOPTIMAL\n"); memset(vis, 0, sizeof(vis)); while(!vis[p]) { vis[p] = 1; p = edge[pre[p]].u; } update(p); for(i = 1; i <= n; i++) { for(j = 1; j < m; j++) printf("%d ", edge[(((i-1)*m+j-1)*2)^1].c); printf("%d\n", edge[(((i-1)*m+j-1)*2)^1].c); } } int main() { int i, j; int z; while( ~scanf("%d%d", &n, &m)) { S = 0; T = n+m+1; init(); memset(b, 0, sizeof(b)); for(i = 1; i <= n; i++) scanf("%d%d%d", &ax[i], &ay[i], &ac[i]); for(i = 1; i <= m; i++) scanf("%d%d%d", &bx[i], &by[i], &bc[i]); for(i = 1; i <= n; i++) for(j = 1; j <= m; j++) { scanf("%d", &z); b[j] += z; add(i, j+n, ac[i]-z, z, Dis(i, j)); } for(i = 1; i <= m; i++) add(i+n, T, bc[i]-b[i], b[i], 0); solve(); } return 0; }


浙公网安备 33010602011771号