您的位置:首页 > 理论基础 > 计算机网络

网络流24题之二十四 骑士共存 最大独立集

2016-03-29 21:33 357 查看
问题描述:

在一个 n*n 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘

上某些方格设置了障碍,骑士不得进入。

编程任务:

对于给定的 n*n 个方格的国际象棋棋盘和障碍标志, 计算棋盘上最多可以放置多少个骑

士,使得它们彼此互不攻击。

数据输入:

由文件 input.txt 给出输入数据。第一行有 2 个正整数 n 和 m (1<=n<=200, 0<=m<n 2 ),

分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障

碍的方格坐标。

结果输出:

将计算出的共存骑士数输出到文件 output.txt。

输入文件示例 输出文件示例

input.txt

3 2

1 1

3 3

output.txt

5

【问题分析】

二分图最大独立集,转化为二分图最大匹配,从而用最大流解决。

【建模方法】

首先把棋盘黑白染色,使相邻格子颜色不同。把所有可用的黑色格子看做二分图X集合中顶点,可用的白色格子看做Y集合顶点。建立附加源S汇T,从S向X集合中每个顶点连接一条容量为1的有向边,从Y集合中每个顶点向T连接一条容量为1的有向边。从每个可用的黑色格子向骑士一步能攻击到的可用的白色格子连接一条容量为无穷大的有向边。求出网络最大流,要求的结果就是可用格子的数量减去最大流量。

代码:

const
dx:array[1..8] of longint=(1,1,-1,-1,2,2,-2,-2);
dy:array[1..8] of longint=(2,-2,2,-2,1,-1,1,-1);

var
n,m,x,y,i,j,k,ans,e,s,t:longint;
cur,last,d,num,fa:array[0..50000] of longint;
a:array[1..200,1..200] of boolean;
side:array[1..500000] of record
x,y,c,op,next:longint;
end;

procedure add(x,y,c:longint);
begin
inc(e);
side[e].x:=x; side[e].y:=y; side[e].c:=c; side[e].op:=e+1;
side[e].next:=last[x]; last[x]:=e;
inc(e);
side[e].x:=y; side[e].y:=x; side[e].c:=0; side[e].op:=e-1;
side[e].next:=last[y]; last[y]:=e;
end;

procedure remark(x:longint);
var
min,i:longint;
begin
min:=n*n-m+1;
cur[x]:=last[x];
i:=cur[x];
while i>0 do
with side[i] do
begin
if (c>0)and(d[y]<min) then min:=d[y];
i:=next;
end;
d[x]:=min+1;
end;

procedure change;
var
min,i:longint;
begin
min:=maxlongint;
i:=t;
while i<>s do
with side[fa[i]] do
begin
if c<min then min:=c;
i:=x;
end;
ans:=ans+min;
i:=t;
while i<>s do
with side[fa[i]] do
begin
dec(c,min);
inc(side[op].c,min);
i:=x;
end;
end;

procedure sap;
var
i:longint;
begin
for i:=s to t do
cur[i]:=last[i];
num[0]:=n*n-m+2;
i:=s;
while d[s]<n*n-m+2 do
begin
while cur[i]>0 do
with side[cur[i]] do
if (c>0)and(d[y]+1=d[x])
then break
else cur[i]:=next;
if cur[i]=0
then begin
dec(num[d[i]]);
if num[d[i]]=0 then break;
remark(i);
inc(num[d[i]]);
if i<>s then i:=side[fa[i]].x;
end
else begin
fa[side[cur[i]].y]:=cur[i];
i:=side[cur[i]].y;
if i=t then
begin
change;
i:=s;
end;
end;
end;
end;

begin
assign(input,'kni.in');
assign(output,'kni.out');
reset(input);
rewrite(output);
readln(n,m);
fillchar(a,sizeof(a),true);
for i:=1 to m do
begin
readln(x,y);
a[x,y]:=false;
end;
s:=0;
t:=n*n+1;
for i:=1 to n do
for j:=1 to n do
if (i mod 2=j mod 2)and(a[i,j])
then begin
for k:=1 to 8 do
begin
x:=i+dx[k];
y:=j+dy[k];
if (x<1)or(x>n)or(y<1)or(y>n) then continue;
if a[x,y]=false then continue;
add((i-1)*n+j,(x-1)*n+y,1);
end;
add(s,(i-1)*n+j,1);
end
else if a[i,j] then add((i-1)*n+j,t,1);
sap;
writeln(n*n-m-ans);
close(input);
close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: