首页 > 代码库 > 【Codevs1907】方格取数3(最小割)

【Codevs1907】方格取数3(最小割)

题意:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任
意2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。

n,m<=30

思路:如果将棋盘黑白点染色,可以发现相邻的黑白点不能同时取

将源点到黑点连一条容量为黑点数字的边,黑点到相邻白点连容量为∞的边,白点到汇点连容量为白点数字的边,可以发现如果不让相邻黑白点同时取到,三条边中必定要切断一条

题意就是让切断的总和最小,所以显然不会切∞,只会切另外两条

跑最小割即可

 

  1 const dx:array[1..4]of longint=(-1,1,0,0);
  2       dy:array[1..4]of longint=(0,0,-1,1);
  3 var fan:array[1..200000]of longint;
  4     head,vet,next,len,gap,dis:array[0..20000]of longint;
  5     a,b,num:array[1..50,1..50]of longint;
  6     n,m,i,j,tot,source,src,s,sum,k,x,y:longint;
  7 
  8 function min(x,y:longint):longint;
  9 begin
 10  if x<y then exit(x);
 11  exit(y);
 12 end;
 13 
 14 procedure add(a,b,c:longint);
 15 begin
 16  inc(tot);
 17  next[tot]:=head[a];
 18  vet[tot]:=b;
 19  len[tot]:=c;
 20  head[a]:=tot;
 21 
 22  inc(tot);
 23  next[tot]:=head[b];
 24  vet[tot]:=a;
 25  len[tot]:=0;
 26  head[b]:=tot;
 27 end;
 28 
 29 function dfs(u,aug:longint):longint;
 30 var e,v,t,val,flow:longint;
 31 begin
 32  if u=src then exit(aug);
 33  e:=head[u]; val:=s-1; flow:=0;
 34  while e<>0 do
 35  begin
 36   v:=vet[e];
 37   if len[e]>0 then
 38   begin
 39    if dis[u]=dis[v]+1 then
 40    begin
 41     t:=dfs(v,min(len[e],aug-flow));
 42     len[e]:=len[e]-t;
 43     len[fan[e]]:=len[fan[e]]+t;
 44     flow:=flow+t;
 45     if dis[source]>=s then exit(flow);
 46     if aug=flow then break;
 47    end;
 48    val:=min(val,dis[v]);
 49   end;
 50   e:=next[e];
 51  end;
 52  if flow=0 then
 53  begin
 54   dec(gap[dis[u]]);
 55   if gap[dis[u]]=0 then dis[source]:=s;
 56   dis[u]:=val+1;
 57   inc(gap[dis[u]]);
 58  end;
 59  exit(flow);
 60 end;
 61 
 62 
 63 function maxflow:longint;
 64 var ans:longint;
 65 begin
 66  fillchar(gap,sizeof(gap),0);
 67  fillchar(dis,sizeof(dis),0);
 68  gap[0]:=s; ans:=0;
 69  while dis[source]<s do ans:=ans+dfs(source,maxlongint);
 70  exit(ans);
 71 end;
 72 
 73 begin
 74  assign(input,Codevs1907.in); reset(input);
 75  assign(output,Codevs1907.out); rewrite(output);
 76  readln(n,m);
 77  for i:=1 to 200000 do
 78   if i mod 2=1 then fan[i]:=i+1
 79    else fan[i]:=i-1;
 80  for i:=1 to n do
 81   for j:=1 to m do
 82   begin
 83    read(a[i,j]); sum:=sum+a[i,j];
 84    inc(s); num[i,j]:=s; b[i,j]:=(i+j+1) mod 2;
 85   end;
 86  for i:=1 to n do
 87   for j:=1 to m do
 88    if b[i,j]=1 then
 89     for k:=1 to 4 do
 90     begin
 91      x:=i+dx[k]; y:=j+dy[k];
 92      if (x>0)and(x<=n)and(y>0)and(y<=m) then
 93      begin
 94       add(num[i,j],num[x,y],maxlongint);
 95       //writeln(i, ,j, ,x, ,y);
 96      end;
 97     end;
 98  source:=s+1; src:=s+2; s:=s+2;
 99  for i:=1 to n do
100   for j:=1 to m do
101    if b[i,j]=1 then
102    begin
103     //writeln(source, ,i, ,j);
104     add(source,num[i,j],a[i,j]);
105    end
106     else
107     begin
108      //writeln(i, ,j, ,src);
109      add(num[i,j],src,a[i,j]);
110     end;
111  writeln(sum-maxflow);
112 
113  close(input);
114  close(output);
115 end.

 

【Codevs1907】方格取数3(最小割)