一.题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314
二,题目大意:给一个无汇源点,流量有上下界限的图,求出是否有可行流,如果有,输出每条管子上的最大流。
三.思路:首先判断有无可行流,由于流量有上下界,于是,自然而然想到了每条弧用上界减去下界,但是这样违反了流量守恒(流入一个节点的流等于流出的)。
比如说:(u,v)上下界为(1,3), (v, q)上下界为(3,4)一条边减去2,另一条边减去了1,减去的流量不相等,相当于1的流量积累在v。于是我们可以想到建立源点、汇点来导流。
具体建图如下:
1.记录每个点的D = (每条进入它的弧的下界) 减去 (由它出发的弧的下界)。如果大于0,得到的就是积累在本节点的流量,于是建立一个汇点,把流导给它。容量为D。如果小于0,得到的就是本节点所需要进入的流量,建立一个源点s,跟它相连,容量为-D。
2.当然原来容量网络的每条弧保持一样,容量变为上界 减去 下界。
对于构造出来的图我们叫它伴随网络,(当然它的每条弧下界都为0)只有伴随网络的最大流使得从源点S出发,每条弧都满了(此时连到T的弧也一定会满),原来网络才有可行流。而本题还要求原容量网络中每条弧的可行流的流量,其实它只等于伴随网络中所对应的弧的流量加上每条弧流量的下界。而对于邻接表建图的话,伴随网络中所对应的弧的流量,就是第2*i条边的反向弧最后的流量。也就是2*i^1。
四.代码:
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <cstdlib> using namespace std; const int INF = 0x3f3f3f3f, MAX_N = 209; class Dinic { public: struct Edge { int v, w, next; }; int cnt, head[MAX_N], dist[MAX_N], s, t; Edge edges[MAX_N*MAX_N]; void init(int is, int it) { cnt = 0; s = is, t = it; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int weight) { edges[cnt] = (Edge){v, weight, head[u]}; head[u] = cnt++; edges[cnt] = (Edge){u, 0, head[v]}; head[v] = cnt++; } bool BFS() { int i, cur; queue <int> que; que.push(s); memset(dist, -1, sizeof(dist)); dist[s] = 0; while(!que.empty()){ cur = que.front(); que.pop(); for(i = head[cur]; i != -1; i = edges[i].next) if(-1 == dist[edges[i].v] && edges[i].w){ dist[edges[i].v] = dist[cur] + 1; que.push(edges[i].v); } } return dist[t] != -1; } int DFS(int start, int curFlow) { if(start == t) return curFlow; int i, minFlow = 0, v, temp; for(i = head[start]; i != -1; i = edges[i].next){ v = edges[i].v; if(dist[start] == dist[v] - 1 && edges[i].w > 0){ temp = DFS(v, min(edges[i].w, curFlow)); edges[i].w -= temp; edges[i^1].w += temp; curFlow -= temp; minFlow += temp; if(0 == curFlow) break; } } if(0 == minFlow) dist[start] = -2; return minFlow; } int maxFlow() { int res = 0; while(BFS()){ res += DFS(s, INF); } return res; } }G; int nodeNum, edgeNum, cnt[MAX_N]; int main() { //freopen("in.txt", "r", stdin); int sum, i, j, test, u, v, down[MAX_N*MAX_N], up, s, t; scanf("%d", &test); while(test--){ scanf("%d%d", &nodeNum, &edgeNum); s = nodeNum + 1, t = nodeNum + 2; G.init(s, t); memset(cnt, 0, sizeof(cnt)); for(i = 0; i < edgeNum; i++){ scanf("%d%d%d%d", &u, &v, &down[i], &up); cnt[u] += down[i], cnt[v] -= down[i]; G.addEdge(u, v, up - down[i]); } sum = 0; for(i = 1; i <= nodeNum; i++){ if(cnt[i] > 0){ G.addEdge(i, t, cnt[i]); sum += cnt[i]; } else if(cnt[i] < 0) G.addEdge(s, i, -cnt[i]); } if(sum == G.maxFlow()){ printf("YES\n"); for(i = 0; i < edgeNum; i++) printf("%d\n", down[i] + G.edges[(2*i)^1].w); printf("\n"); } else printf("NO\n\n"); } return 0; }