您的位置:首页 > 其它

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

2016-12-15 20:01 549 查看

题意:

在一个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.

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: