我们可以对于消费和盈利的点建立二分图,开始答案为所有的盈利和,
那么源向消费的点连边,流量为消费值,盈利向汇连边,流量为盈利值
中间盈利对应的消费连边,流量为INF,那么我们求这张图的最小割,用
开始的答案减去最小割就是答案,因为最小割的存在不是左面就是右面,
割左面,代表建这条路,需要对应的消费,那么割右面代表不要这项盈利,
那本来加进去的盈利应该减掉,所以可以这样更新答案。
/************************************************************** Problem: 1497 User: BLADEVIL Language: Pascal Result: Accepted Time:496 ms Memory:13116 kb ****************************************************************/ //By BLADEVIL var n, m :longint; pre, other, len :array[0..1000010] of longint; last :array[0..100010] of longint; l :longint; source, sink :longint; ans :longint; que, d :array[0..100010] of longint; function min(a,b:longint):longint; begin if a>b then min:=b else min:=a; end; procedure connect(x,y,z:longint); begin inc(l); pre[l]:=last[x]; last[x]:=l; other[l]:=y; len[l]:=z; end; procedure init; var i :longint; x, y, z :longint; begin read(n,m); source:=n+m+2; sink:=source+1; l:=1; for i:=1 to n do begin read(x); connect(source,i,x); connect(i,source,0); end; for i:=n+1 to n+m do begin read(x,y,z); connect(x,i,maxlongint div 10); connect(i,x,0); connect(y,i,maxlongint div 10); connect(i,y,0); connect(i,sink,z); connect(sink,i,0); ans:=ans+z; end; end; function bfs:boolean; var q, p, cur :longint; h, t :longint; begin fillchar(d,sizeof(d),0); h:=0; t:=1; d[source]:=1; que[1]:=source; while h<t do begin inc(h); cur:=que[h]; q:=last[cur]; while q<>0 do begin p:=other[q]; if (len[q]>0) and (d[p]=0) then begin inc(t); que[t]:=p; d[p]:=d[cur]+1; if p=sink then exit(true); end; q:=pre[q]; end; end; exit(false); end; function dinic(x,flow:longint):longint; var tmp, rest :longint; q, p :longint; begin if x=sink then exit(flow); rest:=flow; q:=last[x]; while q<>0 do begin p:=other[q]; if (len[q]>0) and (d[p]=d[x]+1) and (rest>0) then begin tmp:=dinic(p,min(len[q],rest)); dec(rest,tmp); dec(len[q],tmp); inc(len[q xor 1],tmp); end; q:=pre[q]; end; exit(flow-rest); end; procedure main; begin while bfs do ans:=ans-dinic(source,maxlongint div 10); writeln(ans); end; begin init; main; end.