很容易想到是最小割模型
首先对于一个点i,从s到i连一条容量为ai的边,再从i连一条容量为bi的边到t
然后就是处理附加权的问题了
一开始受到之前的思维定势的影响,一直在思考怎么在作物之间连边
由于每种额外收益对应多种作物,而不再是原来bzoj2132的二元关系最小割,这是不行的
所以我们考虑可以把一种组合作物方式看成一个两点u,v,表示同时种在一个A、B田里的两种情况
对于u,我们连边s-->u 容量为c1,再从u向对应每种作物连一条容量inf的边
对于v,我们连边v-->t 容量为c2,再从对应每个作物向v连一条容量inf的边(组合方式是固定的,这些边当然不能割去)
不难发现,做最小割后s-->u,v-->t的容量不能同时保存,
且同时假设保留s-->u 那么对应作物与t的连边一定被割去,相当于对应作物都种在A地中
保留v-->t同理,所以这样建图做最小割是正确的
最终ans=所有收益-mincut
还有种想法我觉得更好的是做最大权闭合子图
首先我们把所有作物都种在A田地里,然后再通过调整选一些作物种在B里取得最优答案
我们把每个额外收益看作一个点,点权为c2-c1,每个作物的点权为bi-ai;
要选取某个作物组合改成种在B里,那么必然所对应的作物也都要种在B里
这就相当于选择一个点集,其中每个点的指向的点也在点集中,使这样一个点权和最大
很容易想到是一个最大权闭合子图问题,最大权闭合子图的做法具体见bzoj1497,这里就不多说
这种调整思路和判断混合图欧拉回路颇有异曲同工之妙
这里采用的是第一种方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 const inf=100000007; 2 type node=record 3 next,flow,point:longint; 4 end; 5 6 var edge:array[0..4000010] of node; 7 p,numh,h,d,cur,pre:array[0..40010] of longint; 8 t,x,y,k,i,j,n,m,len,a,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 i,j,q,tmp,u,neck:longint; 26 begin 27 sap:=0; 28 fillchar(h,sizeof(h),0); 29 numh[0]:=t+1; 30 for i:=0 to t do 31 cur[i]:=p[i]; 32 u:=0; 33 sap:=0; 34 neck:=inf; 35 while h[0]<t+1 do 36 begin 37 d[u]:=neck; 38 i:=cur[u]; 39 while i<>-1 do 40 begin 41 j:=edge[i].point; 42 if (edge[i].flow>0) and (h[u]=h[j]+1) then 43 begin 44 pre[j]:=u; 45 cur[u]:=i; 46 neck:=min(neck,edge[i].flow); 47 u:=j; 48 if u=t then 49 begin 50 sap:=sap+neck; 51 while u<>0 do 52 begin 53 u:=pre[u]; 54 j:=cur[u]; 55 dec(edge[j].flow,neck); 56 inc(edge[j xor 1].flow,neck); 57 end; 58 neck:=inf; 59 end; 60 break; 61 end; 62 i:=edge[i].next; 63 end; 64 if i=-1 then 65 begin 66 dec(numh[h[u]]); 67 if numh[h[u]]=0 then exit; 68 q:=-1; 69 tmp:=t; 70 i:=p[u]; 71 while i<>-1 do 72 begin 73 j:=edge[i].point; 74 if edge[i].flow>0 then 75 if h[j]<tmp then 76 begin 77 q:=i; 78 tmp:=h[j]; 79 end; 80 i:=edge[i].next; 81 end; 82 h[u]:=tmp+1; 83 cur[u]:=q; 84 inc(numh[h[u]]); 85 if u<>0 then 86 begin 87 u:=pre[u]; 88 neck:=d[u]; 89 end; 90 end; 91 end; 92 end; 93 94 begin 95 len:=-1; 96 fillchar(p,sizeof(p),255); 97 readln(n); 98 for i:=1 to n do 99 begin 100 read(x); 101 s:=s+x; 102 add(0,i,x); 103 add(i,0,0); 104 end; 105 readln; 106 for i:=1 to n do 107 begin 108 read(h[i]); 109 s:=s+h[i]; 110 end; 111 readln(m); 112 t:=m*2+n+1; 113 for i:=1 to n do 114 begin 115 add(i,t,h[i]); 116 add(t,i,0); 117 end; 118 for i:=1 to m do 119 begin 120 read(k,x,y); 121 s:=s+x+y; 122 add(0,i+n,x); 123 add(i+n,0,0); 124 add(i+n+m,t,y); 125 add(t,i+n+m,0); 126 for j:=1 to k do 127 begin 128 read(a); 129 add(i+n,a,inf); 130 add(a,i+n,0); 131 add(a,i+n+m,inf); 132 add(i+n+m,a,0); 133 end; 134 readln; 135 end; 136 writeln(s-sap); 137 end.