Codevs1922骑士共存问题(最小割,二分图最大匹配)
Posted myx12345
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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骑士共存问题(最小割,二分图最大匹配)的主要内容,如果未能解决你的问题,请参考以下文章