思考一下我们接触的最小割问题

  1. 最小割的基本问题(可能会和图论的知识相结合,比如bzoj1266,bzoj1797)

  2. 最大权闭合图(bzoj1497)

  3. 最大点权覆盖集,最大点权独立集(bzoj1324)

最近接触到了一类关于最小割新的问题,我也不知道叫什么好

反正它有这么几个特点

  1. 每个点都有两种选择的可能性,设为属于S和属于T,属于S有收益a[i],属于T有收益b[i]

  2. 两点之间可能因为同在一个或不在同一个集合内产生额外的收益

  3. 使收益最大化(废话)

大概就是这个意思,如果看不懂也没关系,我们先从最简单的问题开始分析

首先在满足1的条件下,我们有m对关系,点i和j若同在一个集合,那么就能产生一个额外收益w[i,j];

最终使收益最大化。

对此,我们对于每个点i,我们连s--->i 流量为a[i], i--->t 流量为b[i];

然后对于每对关系(i,j),连i<---j,j--->i 流量都为w[i,j];

然后怎么做呢?根据割的定义,就是s到t没有路

在这里就是,割完之后每个点要么和s连,要么和t连;

我们假如以两个点的图为例,思考一下最小割可能割掉的边(我比较懒,就不发图了)

就会发现,这里的最小割正能使不在一个集合的两个点之间的边被切断

或者使在一个集合的两个点之间的边不被切断

最终ans=∑a[i]+∑b[i]+∑w[i,j]-mincut

这里割对应一种解决问题的方案

 

好这是最初步,下面就是bzoj2132的问题,

条件2变成了,不在同一个集合里的两点会产生一个额外的收益

我们先按基本问题的方式建图

有了最开始的经验,我们不难猜测,

假如选择一个点集,使其中的点i,颠倒一下使s-->i的流量为b[i],i-->t的流量为a[i];

这样我们再做最小割,不就又变回了最基本的问题吗?

而我们应该怎么选择点集呢?

显然,这个点集内部的点是不能有关系的,并且,这些点是给出关系中一侧的点;

说的明确一点,就是不管S,T,根据关系建得的图G,必须是一个二分图;

那么这道题满不满足呢?

我们对平面图黑白相间染色,显然黑点与白点才会产生关系,

黑点与黑点,白点与白点之间是没有关系——是二分图!

于是这道题就简单了!

 1 const dx:array[1..4] of integer=(0,0,1,-1);
 2       dy:array[1..4] of integer=(1,-1,0,0);
 3       inf=100000007;
 4 
 5 type node=record
 6        point,next,flow:longint;
 7      end;
 8 
 9 var edge:array[0..200010] of node;
10     p,cur,h,numh,pre:array[0..10010] of longint;
11     c,num:array[0..110,0..110] of longint;
12     s,x,y,i,j,k,n,m,len,t:longint;
13 
14 procedure add(x,y,f:longint);
15   begin
16     inc(len);
17     edge[len].flow:=f;
18     edge[len].point:=y;
19     edge[len].next:=p[x];
20     p[x]:=len;
21   end;
22 
23 begin
24   len:=-1;
25   fillchar(p,sizeof(p),255);
26   readln(n,m);
27   t:=n*m+1;
28   for i:=1 to n do
29     for j:=1 to m do
30     begin
31       inc(k);
32       num[i,j]:=k;
33       read(x);
34       s:=s+x;
35       if (i+j) mod 2=1 then   //黑白染色
36       begin
37         add(0,k,x);
38         add(k,0,x);
39       end
40       else begin
41         add(k,t,x);
42         add(t,k,0);
43       end;
44     end;
45 
46   for i:=1 to n do
47     for j:=1 to m do
48     begin
49       read(x);
50       s:=s+x;
51       if (i+j) mod 2=1 then
52       begin
53         add(num[i,j],t,x);
54         add(t,num[i,j],x);
55       end
56       else begin
57         add(0,num[i,j],x);
58         add(num[i,j],0,0);
59       end;
60     end;
61   for i:=1 to n do
62     for j:=1 to m do
63       read(c[i,j]);
64   for i:=1 to n do
65     for j:=1 to m do
66       for k:=1 to 4 do
67       begin
68         x:=i+dx[k];
69         y:=j+dy[k];
70         if num[x,y]>0 then
71         begin
72           s:=s+c[i,j];
73           add(num[i,j],num[x,y],c[i,j]+c[x,y]);  //两地建筑物类型不同,增加的额外收益是相互的,一荣俱荣一损俱损
74           add(num[x,y],num[i,j],0);
75         end;
76       end;
77   writeln(s-sap);  //求最大流省略
78 end.
2132

 

下面再扩展这个问题

条件2变为若点i,j同属于S,增加额外收益为w[i,j],

若点i,j同属于T,增加额外收益为r[i,j];  (这就是bzoj2127)

我们对于每个点i,我们连s--->i 流量为a[i], i--->t 流量为b[i];

显然,之前根据关系的建图方法已经不适用了,我们要思考怎么解决同属于S,同属于T所带来的收益

这必须得回到割的意义上来,我们知道割表示损失,我们取不到的

那我们就来分析一下损失:

1. 当i和j同时属于S的时候,我们损失了r[i,j]

2. 当i和j同时属于T的时候,我们损失了w[i,j]

3. 当i,j属于不同的集合,我们损失了w[i,j]+r[i,j]

这有什么用呢?我们可以换一种方式表达

当i属于S时,损失了r[i,j]/2,当j属于S时,损失了r[i,j]/2

当i属于T时,损失了w[i,j]/2,当j属于T时,损失了w[i,j]/2

这样我们再看3,我们还要在增加(w[i,j]+r[i,j])/2的损失

不难发现,问题又变回了最基本的问题

对于点i,我们增加s--->i 流量为r[i,j]/2,t--->i 流量为w[i,j]/2

对于每对关系(i,j),连i<---j,j--->i 流量都为(w[i,j]+r[i,j])/2;

ans=所有可能收益和-mincut

为了方便,我们可以一开始把流量全乘2,最后再除以2即可

友情提示:这道题不加当前弧优化的sap会TLE

 

  1 const inf=1000000007;
  2       dx:array[1..4] of integer=(-1,1,0,0);
  3       dy:array[1..4] of integer=(0,0,-1,1);
  4 
  5 type node=record
  6        point,next,flow:longint;
  7      end;
  8 
  9 var edge:array[0..500010] of node;
 10     d,p,cur,h,numh,pre:array[0..10010] of longint;
 11     a:array[0..110,0..110,1..4] of longint;
 12     num,b,c:array[0..110,0..110] of longint;
 13     n,m,t,s,x,i,j,k,len,y:longint;
 14 
 15 function min(a,b:longint):longint;
 16   begin
 17     if a>b then exit(b) else exit(a);
 18   end;
 19 
 20 procedure add(x,y,f:longint);
 21   begin
 22     inc(len);
 23     edge[len].point:=y;
 24     edge[len].flow:=f;
 25     edge[len].next:=p[x];
 26     p[x]:=len;
 27   end;
 28 
 29 function sap:longint;
 30   var tmp,neck,u,i,j,q:longint;
 31       flag:boolean;
 32 
 33   begin
 34     numh[0]:=t+1;
 35     u:=0;
 36     sap:=0;
 37     cur:=p;
 38     neck:=inf;
 39     while h[0]<t do
 40     begin
 41       d[u]:=neck;
 42       flag:=false;
 43       i:=cur[u];
 44       while i<>-1 do
 45       begin
 46         j:=edge[i].point;
 47         if (edge[i].flow>0) and (h[u]=h[j]+1) then
 48         begin
 49           flag:=true;
 50           neck:=min(neck,edge[i].flow);
 51           cur[u]:=i;
 52           pre[j]:=u;
 53           u:=j;
 54           if u=t then
 55           begin
 56             sap:=sap+neck;
 57             i:=t;
 58             while i<>0 do
 59             begin
 60               i:=pre[i];
 61               j:=cur[i];
 62               dec(edge[j].flow,neck);
 63               inc(edge[j xor 1].flow,neck);
 64             end;
 65             neck:=inf;
 66             u:=0;
 67           end;
 68           break;
 69         end;
 70         i:=edge[i].next;
 71       end;
 72       if not flag then
 73       begin
 74         dec(numh[h[u]]);
 75         if numh[h[u]]=0 then exit;
 76         tmp:=t;
 77         i:=p[u];
 78         q:=0;
 79         while i<>-1 do
 80         begin
 81           j:=edge[i].point;
 82           if (edge[i].flow>0) and (h[j]<tmp) then
 83           begin
 84             q:=i;
 85             tmp:=h[j];
 86           end;
 87           i:=edge[i].next;
 88         end;
 89         cur[u]:=q;
 90         h[u]:=tmp+1;
 91         inc(numh[h[u]]);
 92         if u<>0 then
 93         begin
 94           u:=pre[u];
 95           neck:=d[u];
 96         end;
 97       end;
 98     end;
 99   end;
100 
101 begin
102   readln(n,m);
103   len:=-1;
104   fillchar(p,sizeof(p),255);
105   t:=n*m+1;
106   for i:=1 to n do
107   begin
108     for j:=1 to m do
109     begin
110       inc(k);
111       num[i,j]:=k;
112       read(x);
113       s:=s+x;
114       x:=x shl 1;
115       b[i,j]:=b[i,j]+x;
116     end;
117     readln;
118   end;
119   for i:=1 to n do
120   begin
121     for j:=1 to m do
122     begin
123       read(x);
124       s:=s+x;
125       x:=x shl 1;
126       c[i,j]:=c[i,j]+x;
127     end;
128     readln;
129   end;
130 
131   for i:=1 to n-1 do
132   begin
133     for j:=1 to m do
134     begin
135       read(x);
136       s:=s+x;
137       b[i,j]:=b[i,j]+x;
138       b[i+1,j]:=b[i+1,j]+x;
139       a[i,j,2]:=a[i,j,2]+x;
140       a[i+1,j,1]:=a[i+1,j,1]+x;
141     end;
142     readln;
143   end;
144 
145   for i:=1 to n-1 do
146   begin
147     for j:=1 to m do
148     begin
149       read(x);
150       s:=s+x;
151       c[i,j]:=c[i,j]+x;
152       c[i+1,j]:=c[i+1,j]+x;
153       a[i,j,2]:=a[i,j,2]+x;
154       a[i+1,j,1]:=a[i+1,j,1]+x;
155     end;
156     readln;
157   end;
158 
159   for i:=1 to n do
160   begin
161     for j:=1 to m-1 do
162     begin
163       read(x);
164       s:=s+x;
165       b[i,j]:=b[i,j]+x;
166       b[i,j+1]:=b[i,j+1]+x;
167       a[i,j,4]:=a[i,j,4]+x;
168       a[i,j+1,3]:=a[i,j+1,3]+x;
169     end;
170     readln;
171   end;
172 
173   for i:=1 to n do
174   begin
175     for j:=1 to m-1 do
176     begin
177       read(x);
178       s:=s+x;
179       c[i,j]:=c[i,j]+x;
180       c[i,j+1]:=c[i,j+1]+x;
181       a[i,j,4]:=a[i,j,4]+x;
182       a[i,j+1,3]:=a[i,j+1,3]+x;
183     end;
184     readln;
185   end;
186   for i:=1 to n do
187     for j:=1 to m do
188     begin
189       for k:=1 to 4 do
190       begin
191         x:=i+dx[k];
192         y:=j+dy[k];
193         if num[x,y]>0 then
194         begin
195           add(num[i,j],num[x,y],a[i,j,k]); //注意序号的对应
196           add(num[x,y],num[i,j],0);
197         end;
198       end;
199       add(0,num[i,j],b[i,j]);
200       add(num[i,j],0,0);
201       add(num[i,j],t,c[i,j]);
202       add(t,num[i,j],0);
203     end;
204   writeln(s-sap div 2);
205 end.
2127

这个问题最终阶段是bzoj3438 不再是两点间关系而是多点间关系了

即多个点如果同属A集合会产生一个额外收益c1,同属于B集合会产生一个额外收益c2

这就不能用上述的做法了,具体做法见bzoj3438的解题报告

 

posted on 2014-06-07 16:20  acphile  阅读(134)  评论(0编辑  收藏  举报