[二分图最大独立集][BZOJ 3175][TJOI 2013]攻击装置

Description

Analysis

这道题一开始就想岔了...

可以发现从一个节点出去的马,如果回到该节点的话,经过的节点数一定是偶数(包括自己)。

一开始我想的是既然都是偶数,那么可以用两次DFS分别统计,具体地说就是对一个联通块,先从一个节点DFS,求出答案1,然后再从上一次节点的相邻节点再做一次,求出答案2,去一个最大值。

然后WA3次,我现在还不知道为什么这样是错的。

之后又发现,因为都是偶数环,进行黑白染色不会产生矛盾,然后就是赤裸裸的二分图最大独立集问题了。

二分图最大独立集=顶点数-二分图最小顶点覆盖集=顶点数-二分图最大匹配。

听说匈牙利被卡,就写了SAP,但听说Dinic完艹SAP!?

const
  dx:array[1..8] of longint=(-1,-2,1,2,-1,-2,1,2);
  dy:array[1..8] of longint=(-2,-1,-2,-1,2,1,2,1);
var
  edge,n,i,j,k,x,y,ans,all,vs,vt,num:longint;
  e:array[1..1000000,1..3] of longint;
  fr,d,vd:array[0..40000] of longint;
  a:array[1..200,1..200] of char;
procedure add(x,y,c:longint);
begin
  inc(edge); e[edge,1]:=y; e[edge,2]:=fr[x]; e[edge,3]:=c; fr[x]:=edge;
end;
function get(x,y:longint):longint;
begin
  exit((x-1)*n+y);
end;
function min(a,b:longint):longint;
begin
  if a<b then exit(a) else exit(b);
end;
function dfs(u,flow:longint):longint;
var
  k,tmp:longint;
begin
  if u=vt then exit(flow);
  dfs:=0;
  k:=fr[u];
  while k<>0 do begin
    if (e[k,3]>0) and (d[u]=d[e[k,1]]+1) then begin
      tmp:=dfs(e[k,1],min(e[k,3],flow-dfs));
      inc(dfs,tmp);
      dec(e[k,3],tmp);
      if odd(k) then inc(e[k+1,3],tmp) else inc(e[k-1,3],tmp);
      if dfs=flow then exit;
    end;
    k:=e[k,2];
  end;
  dec(vd[d[u]]);
  if vd[d[u]]=0 then d[vs]:=num;
  inc(d[u]);
  inc(vd[d[u]]);
end;
begin
  readln(n);
  for i:=1 to n do begin
    for j:=1 to n do
      read(a[i,j]);
    readln;
  end;
  vs:=0; vt:=n*n+1; num:=vt+1; vd[0]:=num;
  for i:=1 to n do begin
    for j:=1 to n do begin
      if a[i,j]='1' then continue;
      inc(all);
      if (i+j) and 1=0 then begin
        add(vs,get(i,j),1);
        add(get(i,j),vs,0);
        for k:=1 to 8 do begin
          x:=i+dx[k]; y:=j+dy[k];
          if (x<1) or (y<1) or (x>n) or (y>n) then continue;
          if a[x,y]='1' then continue;
          add(get(i,j),get(x,y),1);
          add(get(x,y),get(i,j),0);
        end;
      end
      else begin
        add(get(i,j),vt,1);
        add(vt,get(i,j),0);
      end;
    end;
  end;
  while d[vs]<num do ans:=ans+dfs(vs,maxlongint);
  writeln(all-ans);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值