很容易想到是最小割模型
首先对于一个点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,这里就不多说
这种调整思路和判断混合图欧拉回路颇有异曲同工之妙

这里采用的是第一种方法

  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.
View Code

 

posted on 2014-12-25 13:26  acphile  阅读(317)  评论(0编辑  收藏  举报