ZOJ 2314 Reactor Cooling 上下界网络流(无源汇可行流)
每条边的容量满足一定的限制,即有一个上限值,也有一个下限值
上界用ci表示,下界用bi表示。
下界是必须流满的,那么对于每一条边,去掉下界后,其自由流为ci– bi。
主要思想:每一个点流进来的流=流出去的流
对于每一个点i,令
Mi= sum(i点所有流进来的下界流)– sum(i点所有流出去的下界流)
如果Mi大于0,代表此点必须还要流出去Mi的自由流,那么我们从源点连一条Mi的边到该点。
如果Mi小于0,代表此点必须还要流进来Mi的自由流,那么我们从该点连一条Mi的边到汇点。
如果求S->T的最大流,看是否满流(S的相邻边都流满)。
满流则有解,否则无解。
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define maxn 410 #define maxm 40003 #define inf 1000000000 int min(int a, int b) { return a < b ? a : b; } struct E { int v, next, c; }edge[maxm]; int head[maxn], tot; int n, m; int S, T; void add(int s, int t, int c) { edge[tot].v = t; edge[tot].c = c; edge[tot].next = head[s]; head[s] = tot++; edge[tot].v = s; edge[tot].c = 0; edge[tot].next = head[t]; head[t] = tot++; } void init() { tot = 0; memset(head, -1, sizeof(head)); } int gap[maxn], dis[maxn], pre[maxn], cur[maxn]; int sap(int s, int t, int vs)// s 源点,t汇点,vs顶点总数 { int i; for(i = 0; i <= vs; i++) { dis[i] = gap[i] = 0; cur[i] = head[i]; } gap[0] = vs; int u = pre[s] = s, maxf = 0, aug = inf, v; while(dis[s] < vs) { loop: for(i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c > 0 && dis[u] == dis[v] + 1) { aug = min(aug, edge[i].c); pre[v] = u; cur[u] = i; u = v; if(u == t) { while(u != s) { u = pre[u]; edge[cur[u]].c -= aug; edge[cur[u]^1].c += aug; } maxf += aug; aug = inf; } goto loop; } } int min_d = vs; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(edge[i].c > 0 && dis[v] < min_d) { min_d = dis[v]; cur[u] = i; } } if( !(--gap[dis[u]])) break; ++gap[dis[u] = min_d + 1]; u = pre[u]; } return maxf; } int in[maxn]; int low[maxm]; int main() { int i, j, cas; int a, b, c; scanf("%d", &cas); while(cas--) { scanf("%d%d", &n, &m); init(); memset(in, 0, sizeof(in)); for(i = 0; i < m; i++) { scanf("%d%d%d%d", &a, &b, &low[i], &c); in[b] += low[i]; in[a] -= low[i]; add(a, b, c - low[i]); } S = 0, T = n+1; for(i = 1; i <= n; i++) { if(in[i] > 0) add(S, i, in[i]); if(in[i] < 0) add(i, T, -in[i]); } sap(S, T, n+2); bool flag = 1; for(i = head[S]; i != -1; i = edge[i].next) { if(edge[i].c > 0) { flag = 0; break;} } if(flag) { printf("YES\n"); for(i = 0; i < m; i++) printf("%d\n", edge[(i<<1)^1].c + low[i]); } else printf("NO\n"); if(cas) puts(""); } return 0; }


浙公网安备 33010602011771号