首页 > 代码库 > 【Codevs1922】骑士共存问题(最小割,二分图最大匹配)

【Codevs1922】骑士共存问题(最小割,二分图最大匹配)

题意:

在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘
上某些方格设置了障碍,骑士不得进入。

技术分享

对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击。

n<=200,m<=n^2

 

思路:经典的二分图最大匹配问题,采用黑白点染色的思想。

如果按照相邻点黑白不同染色,可以发现每次跳到的点必定与现在所在点不同色,二分图最大匹配即可。

这里用最小割来解决,因为不能允许任何黑白点之间的任何一条边有流量,符合最小割的思想。

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

 

【Codevs1922】骑士共存问题(最小割,二分图最大匹配)