有源汇上下界网络流建图:
我们称原图中的源汇点为 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;
}