这道题让我涨姿势了
对于这类问题,我们称作最大权闭合图问题
就是每个点都有一个点权,要求选择一个点集,其中每个点的指向的点也在点集中,使这样一个点权和最大
对于这种问题,我们添加源点s,汇点t
对于点i,如果点权w是正的,我们连边s--->i,流量为w
如果点权w是负的,我们连边i--->t,流量为-w
然后我们我们原图中所有边流量设为inf即可
最后的答案=正点权和-最小割(最大流)
对于这道题,我们把用户和中转站看成点,
对于每个用户,我们显然要由它指向对应的两个中转站,然后做最大权闭合图即可
但是,这样做会tle,
分析一下,为什么呢?因为有多达50000个用户
再仔细观察题目,一共最多只有5000个中转站,
我们知道,最大流的效率取决于找增广路的效率
对于这幅图,我们不难发现,瓶颈边更容易出现在中转站一边
于是我们可以反向建图,这不改变网络的最小割,并且能大大减少增广的次数
反向建图是一个很重要的优化方法
1 const inf=10000007; 2 type node=record 3 next,flow,point:longint; 4 end; 5 6 var edge:array[0..2000010] of node; 7 p,h,numh,cur,pre:array[0..60010] of longint; 8 n,m,i,j,t,x,y,z,len,s:longint; 9 10 function min(a,b:longint):longint; 11 begin 12 if a>b then exit(b) else exit(a); 13 end; 14 15 procedure add(x,y,f:longint); 16 begin 17 inc(len); 18 edge[len].point:=y; 19 edge[len].flow:=f; 20 edge[len].next:=p[x]; 21 p[x]:=len; 22 end; 23 24 function sap:longint; 25 var u,i,j,q,neck,tmp,s:longint; 26 begin 27 u:=0; 28 numh[0]:=t+1; 29 sap:=0; 30 while h[0]<t+1 do 31 begin 32 if u=t then 33 begin 34 neck:=inf; 35 i:=0; 36 while i<>t do 37 begin 38 j:=cur[i]; 39 if neck>edge[j].flow then 40 begin 41 neck:=edge[j].flow; 42 s:=i; 43 end; 44 i:=edge[j].point; 45 end; 46 i:=0; 47 while i<>t do 48 begin 49 j:=cur[i]; 50 dec(edge[j].flow,neck); 51 inc(edge[j xor 1].flow,neck); 52 i:=edge[j].point; 53 end; 54 sap:=sap+neck; 55 u:=s; 56 end; 57 q:=-1; 58 i:=p[u]; 59 while i<>-1 do 60 begin 61 j:=edge[i].point; 62 if (edge[i].flow>0) and (h[u]=h[j]+1) then 63 begin 64 q:=i; 65 break; 66 end; 67 i:=edge[i].next; 68 end; 69 if q<>-1 then 70 begin 71 cur[u]:=i; 72 pre[j]:=u; 73 u:=j; 74 end 75 else begin 76 dec(numh[h[u]]); 77 if numh[h[u]]=0 then exit; 78 tmp:=t+1; 79 i:=p[u]; 80 while i<>-1 do 81 begin 82 j:=edge[i].point; 83 if edge[i].flow>0 then tmp:=min(tmp,h[j]); 84 i:=edge[i].next; 85 end; 86 h[u]:=tmp+1; 87 inc(numh[h[u]]); 88 if u<>0 then u:=pre[u]; 89 end; 90 end; 91 end; 92 93 begin 94 readln(n,m); 95 t:=n+m+1; 96 len:=-1; 97 fillchar(p,sizeof(p),255); 98 for i:=1 to n do 99 begin 100 read(x); 101 add(0,i,x); 102 add(i,0,0); 103 end; 104 for i:=1 to m do 105 begin 106 readln(x,y,z); 107 s:=s+z; 108 add(n+i,t,z); 109 add(t,n+i,0); 110 add(x,n+i,inf); 111 add(n+i,x,0); 112 add(y,n+i,inf); 113 add(n+i,y,0); 114 end; 115 writeln(s-sap); 116 end.