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

来源:互联网 发布:简繁体转换软件 编辑:程序博客网 时间:2024/05/07 18:10
问题描述:
在一个 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.


0 0
原创粉丝点击