有源汇上下界网络流建图:
我们称原图中的源汇点为 from, to
称我们手动附加的源汇点为 S, T
1、首先由给定的图建好上界的边
2、for(i = from; i <= to; i++) if(in[i] > 0) add( S, i, in[i]);
如此把原图中所有点(包括 from, to )按照无源汇上下界与 S,T 连边
3、加一条 边 add(to, from, inf);
建图完成。
跑一遍网络流 maxflow = dinic( S, T);
很显然若存在一个可行流:1、则于S相连的边必须满流 2、或者 maxflow == sum(in[i] (if in[i]>0) )
此时我们就得到了一个 从 from -> to 的一个可行流(并不是最大流)
我们再恢复原图(就是删除第3条) 通过 add(to, from, -inf) 来删除
再跑一遍网络流 dinic(from, to); 即得到 从from->to的一个最大流
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<queue> #include<vector> using namespace std; #define ll int #define N 10004 #define M 105000 #define inf 1073741824 #define inf64 1152921504606846976 struct Edge{ ll from, to, cap, nex, max; }edge[M*4];//注意这个一定要够大 不然会re 还有反向弧 ll head[N], edgenum; void add(ll u, ll v, ll cap){ Edge E = { u, v, cap, head[u],cap}; edge[ edgenum ] = E; head[u] = edgenum ++; Edge E2= { v, u, 0, head[v],cap}; edge[ edgenum ] = E2; head[v] = edgenum ++; } ll sign[N]; bool BFS(ll from, ll to){ memset(sign, -1, sizeof(sign)); sign[from] = 0; queue<ll>q; q.push(from); while( !q.empty() ){ int u = q.front(); q.pop(); for(ll i = head[u]; i!=-1; i = edge[i].nex) { ll v = edge[i].to; if(sign[v]==-1 && edge[i].cap) { sign[v] = sign[u] + 1, q.push(v); if(sign[to] != -1)return true; } } } return false; } ll Stack[N], top, cur[N]; ll dinic(ll from, ll to){ ll ans = 0; while( BFS(from, to) ) { memcpy(cur, head, sizeof(head)); ll u = from; top = 0; while(1) { if(u == to) { ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边 for(ll i = 0; i < top; i++) if(flow > edge[ Stack[i] ].cap) { flow = edge[Stack[i]].cap; loc = i; } for(ll i = 0; i < top; i++) { edge[ Stack[i] ].cap -= flow; edge[Stack[i]^1].cap += flow; } ans += flow; top = loc; u = edge[Stack[top]].from; } for(ll i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标 if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break; if(cur[u] != -1) { Stack[top++] = cur[u]; u = edge[ cur[u] ].to; } else { if( top == 0 )break; sign[u] = -1; u = edge[ Stack[--top] ].from; } } } return ans; } int n, m; int in[M]; int ST[M], sig[M]; void init(){memset(in, 0, sizeof in);memset(head,-1,sizeof head);edgenum = 0;} int main(){ int i, j, u, v, cap, peo, maxpic; while(~scanf("%d %d",&n,&m)){ init(); int from = 0, to = n+m+1; for(i = 1; i <= m; i++){ scanf("%d",&cap); add(i+n, to, inf); in[to] += cap; in[i+n] -= cap; } int TOP = 0; for(i = 1; i <= n; i++) { scanf("%d %d",&peo, &maxpic); add(from, i, maxpic); while(peo--) { int num, Min, Max; scanf("%d %d %d",&num, &Min, &Max); add(i, num+n+1, Max-Min); in[i] -= Min; in[num+n+1] += Min; sig[TOP] = edgenum-2; ST[TOP++] = Min; } } add(to, from, inf); int S = to +1, T = to +2; int sum = 0; for(i = from; i <= to; i++) { if(in[i] > 0) add(S, i, in[i]), sum += in[i]; else add(i, T, -in[i]); } ll maxflow = dinic(S, T); if(sum != maxflow)puts("-1"); else { maxflow = dinic(from, to); add(to, from, -inf); int cnt = 0; for(i = head[from]; ~i; i = edge[i].nex) cnt += edge[i^1].cap; printf("%d\n", cnt); for(i = 0; i < TOP; i++)printf("%d\n", edge[sig[i]^1].cap + ST[i]); } puts(""); } return 0; }