[2017雅礼集训]day2 T2 二分图关键点&&博弈

首先看到棋盘就要想到二分图模型。
建出二分图,考虑求出了一个最大匹配,假如Alice把棋放在一个未匹配点上,Bob无论如何都会走到一个匹配点上,然后Alice每次都可以选择走匹配边,直到Bob输。
所以只要求出这个图的所有非关键点(存在一种最大匹配不包含该点),都是Alice的必胜点。
求非关键点的方法:先求出最大匹配,首先对一侧,所有未匹配点能走交错路到的点都是非关键点,在对另一侧做同样的操作。
代码:

type
  edge=^edgenode;
  edgenode=record
    t:longint;
    next:edge;
  end;

var
  n,m,i,j,ans:longint;
  c:char;
  b,visit,unkey:array[0..10100]of boolean;
  link:array[0..10100]of longint;
  con:array[0..10100]of edge;
procedure ins(x,y:longint);
var
  p:edge;
begin
  if b[x] and b[y]=false then exit;
  new(p);
  p^.t:=y;
  p^.next:=con[x];
  con[x]:=p;

  new(p);
  p^.t:=x;
  p^.next:=con[y];
  con[y]:=p;
end;
function pipei(x:longint):boolean;
var
  p:edge;
begin
  pipei:=false;
  p:=con[x];
  while p<>nil do
  begin
    if visit[p^.t]=false then
    begin
      visit[p^.t]:=true;
      if (link[p^.t]=-1)or(pipei(link[p^.t])=true) then begin link[p^.t]:=x; exit(true); end;
    end;
    p:=p^.next;
  end;
end;
procedure dfs(v:longint);
var
  p:edge;
begin
  if v=-1 then exit;
  visit[v]:=true;
  unkey[v]:=true;
  inc(ans);
  p:=con[v];
  while p<>nil do
  begin
    if (link[v]<>p^.t)and(link[p^.t]<>-1)and(visit[link[p^.t]]=false) then dfs(link[p^.t]);
    p:=p^.next;
  end;
end;
begin
  readln(n,m);
  for i:=1 to n*m do
  begin
      read(c);
      if c='#' then b[i]:=false
      else b[i]:=true;
      if i mod m=0 then readln;
  end;
  for i:=1 to n*m do
  begin
    if i mod m<>1 then ins(i,i-1);
    if i mod m<>0 then ins(i,i+1);
    if i-m>0 then ins(i,i-m);
    if i+m<=n*m then ins(i,i+m);
  end;
  for i:=1 to n*m do
    link[i]:=-1;
  for i:=1 to n*m do
  if ((i-1) div m+(i-1) mod m)mod 2=0 then
    begin
      fillchar(visit,sizeof(visit),false);
      pipei(i);
    end;
  for i:=1 to n*m do
    if link[i]<>-1 then link[link[i]]:=i;

  fillchar(unkey,sizeof(unkey),false);
  fillchar(visit,sizeof(visit),false);
  ans:=0;
  for i:=1 to n*m do
    if (b[i]=true)and(link[i]=-1)and(visit[i]=false) then dfs(i);
  writeln(ans);
  for i:=1 to n*m do
    if (unkey[i]=true)and(b[i]=true) then writeln((i-1) div m+1,' ',(i-1) mod m+1);
  readln;

end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值