给出一个N*N的棋盘,在上面有M个位置不能放马,
马的行走方式如下图:
求互相不攻击的马最多能放多少个。
n≤200
匈牙利算法:
这题我们分析发现要求的就是最大独立集,因为有证明得出,最大独立集合=|V|-最大匹配数
而题目很明显最多只能放20000个马,所以我们可以去做二分图匹配,当时20000*20000的数组很明显并不能实现,所以我们发现每个马的攻击点是可求的,所以我们在匹配过程中去寻找连边即可
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
v:array [0..201,0..201] of boolean;
p:array [0..201,0..201] of longint;
xq:array [0..20001,1..2] of longint;
link:array [0..20001] of longint;
cover:array [0..20001] of boolean;
ans,see,you,i,j,n,m,x,y:longint;
function check(aa,bb:longint):boolean;
begin
if (aa<1) or (aa>n) or (bb<1) or (bb>n) then exit(false);
if (v[aa,bb]) or (cover[p[aa,bb]]) then exit(false);
exit(true);
end;
function find(x:longint):boolean;
var
q,i,x1,y1,k:longint;
begin
for i:=1 to 8 do
begin
x1:=xq[x,1]+dx[i];
y1:=xq[x,2]+dy[i];
if check(x1,y1) then
begin
k:=p[x1,y1];
q:=link[k];
link[k]:=x;
cover[k]:=true;
if (q=0) or (find(q)) then exit(true);
link[k]:=q;
end;
end;
exit(false);
end;
begin
readln(n,m);
for i:=1 to m do
begin
readln(x,y);
v[x,y]:=true;
end;
for i:=1 to n do
for j:=1 to n do
if not(v[i,j]) then
begin
if (i+j) mod 2<>0
then begin
inc(see);
p[i,j]:=see;
end
else begin
inc(you);
p[i,j]:=you;
xq[you,1]:=i;
xq[you,2]:=j;
end;
end;
ans:=n*n-m;
for i:=1 to you do
begin
fillchar(cover,sizeof(cover),false);
if find(i) then dec(ans);
end;
writeln(ans);
end.