分析:首先必须得想到,国际象棋的棋盘是分黑白的,也就是一格黑一格白这样。然后每只马能攻击到的位置一定是与它所在的格子异色的格子。所以我们就把棋盘根据颜色构造二分图。然后题目要求的是最多的马不能互相攻击,也就是所谓的最大独立集。而二分图中的最大独立集等于总数减去最大匹配数。
而码完后我发现数组不够,因为二分图每边最多有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 n,m,x,y,i,j,white,black,ans,k:longint; v1:array[1..200,1..200] of boolean; v:array[1..20000] of boolean; num:array[1..200,1..200] of longint; link:array[1..20000] of longint; b,w:array[1..20000,1..2] of longint; function find(x1:longint):boolean; var p,i,s,x,y:longint; begin find:=false; for i:=1 to 8 do begin x:=b[x1,1]+dx[i]; y:=b[x1,2]+dy[i]; if (x<1)or(x>n)or(y<1)or(y>n) then continue; if v1[x,y]=false then continue; s:=num[x,y]; if v[s] then begin p:=link[s]; link[s]:=x1; v[s]:=false; if (p=0)or(find(p)) then exit(true); link[s]:=p; end; end; end; begin readln(n,m); fillchar(v1,sizeof(v1),true); for i:=1 to m do begin readln(x,y); v1[x,y]:=false; end; for i:=1 to n do for j:=1 to n do begin if v1[i,j]=false then continue; if (i mod 2=1)and(j mod 2=0)or(i mod 2=0)and(j mod 2=1) then begin inc(white); w[white,1]:=i; w[white,2]:=j; num[i,j]:=white; end else begin inc(black); b[black,1]:=i; b[black,2]:=j; num[i,j]:=black; end; end; for i:=1 to black do begin fillchar(v,sizeof(v),true); if find(i) then inc(ans); end; writeln(white+black-ans); end.