Description
Input
Output
题目大意:用n个点,m条有向边,每条边有一个容量的上下界,求一个可行流,要求每个点的入流等于出流。
思路:记f[i] = ∑(u,i) - ∑(i,v),其中∑(u,i)为进入i的所有边的容量下界之和,∑(i,v)为离开i的所有边的容量下界之和。建立源点S汇点T,若f[i] ≥ 0,建一条边S→i,容量为f[i];若f[i] < 0,建一条边i→T,容量为f[i]的绝对值。对每一条边i→j,建一条边i→j,容量为上界减去下界。若最大流能使与S关联的边和与T关联的边都满流,则存在可行流,其中每条边的流量为其下界加上最大流图中的流量,否则不存在可行流。
小证明:上面的构图法乍看之下不知道为什么是对的,网上数学证明一大堆我就不说了(虽然都一样),现在我讲一种比较直观的理解。
对每一条边a→b,容量上界为up,下界为down。从S建一条边到b,容量为down;从a建一条边到T,容量为down;从a到b建一条边,容量为up-down。这样建图,若与S→b,a→T的流量都是满的,那么在原图中,我们就可以把S→b,a→T的流量换成是a→b的流量(a有down的流出,b有down的流入,满足把a有的流出,b有的流入放入边a→b,就满足了边的下界)。
之后,若对每一条边的两个点都建边到源点汇点太浪费了,所以源点S到某点i的边可以合起来,容量为∑(u,i);同样,某点i到汇点T的边也可以合起来,容量为∑(i,v);那么对每一个点i,都有从源点到i的边,从i到汇点的边,因为这两条边直接相连,我们只需要像上面构图所说的方法一样,保留一条就可以了。
代码(15MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 using namespace std; 6 7 const int MAXN = 210; 8 const int MAXE = MAXN * MAXN; 9 const int INF = 0x3fff3fff; 10 11 struct SAP { 12 int head[MAXN], gap[MAXN], dis[MAXN], cur[MAXN], pre[MAXN]; 13 int to[MAXE], next[MAXE], flow[MAXE], cap[MAXE]; 14 int n, ecnt, st, ed; 15 16 void init() { 17 memset(head, 0, sizeof(head)); 18 ecnt = 2; 19 } 20 21 void add_edge(int u, int v, int c) { 22 to[ecnt] = v; cap[ecnt] = c; flow[ecnt] = 0; next[ecnt] = head[u]; head[u] = ecnt++; 23 to[ecnt] = u; cap[ecnt] = 0; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++; 24 //printf("%d->%d %d\n", u, v, c); 25 } 26 27 void bfs() { 28 memset(dis, 0x3f, sizeof(dis)); 29 queue<int> que; que.push(ed); 30 dis[ed] = 0; 31 while(!que.empty()) { 32 int u = que.front(); que.pop(); 33 ++gap[dis[u]]; 34 for(int p = head[u]; p; p = next[p]) { 35 int &v = to[p]; 36 if(cap[p ^ 1] && dis[v] > n) { 37 dis[v] = dis[u] + 1; 38 que.push(v); 39 } 40 } 41 } 42 } 43 44 int Max_flow(int ss, int tt, int nn) { 45 st = ss, ed = tt, n = nn; 46 int ans = 0, minFlow = INF, u; 47 for(int i = 0; i <= n; ++i) { 48 cur[i] = head[i]; 49 gap[i] = 0; 50 } 51 u = pre[st] = st; 52 bfs(); 53 while(dis[st] < n) { 54 bool flag = false; 55 for(int &p = cur[u]; p; p = next[p]) { 56 int &v = to[p]; 57 if(cap[p] > flow[p] && dis[u] == dis[v] + 1) { 58 flag = true; 59 minFlow = min(minFlow, cap[p] - flow[p]); 60 pre[v] = u; 61 u = v; 62 if(u == ed) { 63 ans += minFlow; 64 while(u != st) { 65 u = pre[u]; 66 flow[cur[u]] += minFlow; 67 flow[cur[u] ^ 1] -= minFlow; 68 } 69 minFlow = INF; 70 } 71 break; 72 } 73 } 74 if(flag) continue; 75 int minDis = n - 1; 76 for(int p = head[u]; p; p = next[p]) { 77 int &v = to[p]; 78 if(cap[p] > flow[p] && dis[v] < minDis) { 79 minDis = dis[v]; 80 cur[u] = p; 81 } 82 } 83 if(--gap[dis[u]] == 0) break; 84 ++gap[dis[u] = minDis + 1]; 85 u = pre[u]; 86 } 87 return ans; 88 } 89 } G; 90 91 int n, m; 92 int f[MAXN]; 93 int m_id[MAXE], m_down[MAXE]; 94 95 int main() { 96 scanf("%d%d", &n, &m); 97 G.init(); 98 int a, b, c, d, sum = 0; 99 for(int i = 1; i <= m; ++i) { 100 scanf("%d%d%d%d", &a, &b, &d, &c); 101 f[a] -= d; 102 f[b] += d; 103 m_down[i] = d; 104 m_id[i] = G.ecnt; 105 G.add_edge(a, b, c - d); 106 } 107 int ss = n + 1, tt = n + 2; 108 for(int i = 1; i <= n; ++i) { 109 if(f[i] >= 0) G.add_edge(ss, i, f[i]), sum += f[i]; 110 else G.add_edge(i, tt, -f[i]); 111 } 112 if(G.Max_flow(ss, tt, tt) != sum) { 113 puts("NO"); 114 return 0; 115 } 116 puts("YES"); 117 for(int i = 1; i <= m; ++i) printf("%d\n", m_down[i] + G.flow[m_id[i]]); 118 }