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.