SSL 1344 Knights 最大匹配

来源:互联网 发布:淘宝比较好的日本代购 编辑:程序博客网 时间:2024/06/05 11:00
一张大小为n*n的国际象棋棋盘,上面有一些格子被拿走了,棋盘规模n不超过200。马的攻击方向如下图,其中S处为马位置,标有X的点为该马的攻击点。

你的任务是确定在这个棋盘上放置尽可能多的马,并使他们不互相攻击。

分析:首先必须得想到,国际象棋的棋盘是分黑白的,也就是一格黑一格白这样。然后每只马能攻击到的位置一定是与它所在的格子异色的格子。所以我们就把棋盘根据颜色构造二分图。然后题目要求的是最多的马不能互相攻击,也就是所谓的最大独立集。而二分图中的最大独立集等于总数减去最大匹配数。

而码完后我发现数组不够,因为二分图每边最多有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.


0 0
原创粉丝点击