二分图匹配程序总是很简单,这道题却做得很窝囊,5WA居然是把s打成了i...

建图:1,可以把带‘*’格横纵坐标之和为偶数的为集合A,奇数为集合B,这样ans=‘*’个数-最大匹配数,2,也可以直接把所有相邻‘*’格直接连边,(i,j之间和j,i之间都要连)ans=‘*’个数-最大匹配数/2

建图法1:

program poj3020;
type
  node=record
    x,y,next:integer;
  end;
  node1=record
    x,y:integer;
  end;
var
  la,lb,tot,h,w,i,m,k,ans:integer;
  a,b:array[1..400] of node1;
  g:array[1..160000] of node;
  used:array[1..400] of boolean;
  link,first:array[1..400] of integer;
procedure init;
var
  i,j:integer;
  c:char;
begin
  readln(h,w);
  for i:=1 to h do
  begin
    for j:=1 to w do
    begin
      read(c);
      if c='*' then
      begin
        if (i+j) mod 2=0 then
        begin
          inc(la);
          a[la].x:=i;
          a[la].y:=j;
        end
        else
        begin
          inc(lb);
          b[lb].x:=i;
          b[lb].y:=j;
        end;
      end;
    end;
    readln;
  end;
  for i:=1 to la do
    first[i]:=-1;
  for i:=1 to la do
    for j:=1 to lb do
      if ((abs(a[i].x-b[j].x)=1) and (a[i].y=b[j].y)) or ((a[i].x=b[j].x) and (abs(a[i].y-b[j].y)=1)) then
      begin
        inc(tot);
        g[tot].x:=i;
        g[tot].y:=j;
        g[tot].next:=first[i];
        first[i]:=tot;
      end;
end;
function find(s:integer):boolean;
var
  temp:integer;
begin
  temp:=first[s];
  find:=true;
  while temp<>-1 do
  begin
    if used[g[temp].y] then
    begin
      used[g[temp].y]:=false;
      if (link[g[temp].y]=0) or find(link[g[temp].y]) then
      begin
        link[g[temp].y]:=s;
        exit;
      end;
    end;
    temp:=g[temp].next;
  end;
  find:=false;
end;
begin
  readln(m);
  for k:=1 to m do
  begin
    fillchar(a,sizeof(a),0);
    fillchar(g,sizeof(g),0);
    fillchar(link,sizeof(link),0);
    fillchar(first,sizeof(first),0);
    tot:=0;
    la:=0;
    lb:=0;
    init;
    for i:=1 to la do
    begin
      fillchar(used,sizeof(used),true);
      find(i);
    end;
    ans:=0;
    for i:=1 to lb do
      if link[i]<>0 then inc(ans);
    writeln(la+lb-ans);
  end;
end.

建图法2:

program poj3020;
type
  node=record
    x,y,next:integer;
  end;
  node1=record
    x,y:integer;
  end;
var
  l,tot,h,w,i,m,k,ans:integer;
  a:array[1..400] of node1;
  g:array[1..320000] of node;
  used:array[1..400] of boolean;
  link,first:array[1..400] of integer;
procedure init;
var
  i,j:integer;
  c:char;
begin
  readln(h,w);
  for i:=1 to h do
  begin
    for j:=1 to w do
    begin
      read(c);
      if c='*' then
      begin
        inc(l);
        a[l].x:=i;
        a[l].y:=j;
      end;
    end;
    readln;
  end;
  for i:=1 to l do
    first[i]:=-1;
  for i:=1 to l do
    for j:=1 to l do
      if ((abs(a[i].x-a[j].x)=1) and (a[i].y=a[j].y)) or ((a[i].x=a[j].x) and (abs(a[i].y-a[j].y)=1)) then
      begin
        inc(tot);
        g[tot].x:=i;
        g[tot].y:=j;
        g[tot].next:=first[i];
        first[i]:=tot;
      end;
end;
function find(s:integer):boolean;
var
  temp:integer;
begin
  temp:=first[s];
  find:=true;
  while temp<>-1 do
  begin
    if used[g[temp].y] then
    begin
      used[g[temp].y]:=false;
      if (link[g[temp].y]=0) or find(link[g[temp].y]) then
      begin
        link[g[temp].y]:=s;
        exit;
      end;
    end;
    temp:=g[temp].next;
  end;
  find:=false;
end;
begin
  readln(m);
  for k:=1 to m do
  begin
    fillchar(a,sizeof(a),0);
    fillchar(g,sizeof(g),0);
    fillchar(link,sizeof(link),0);
    fillchar(first,sizeof(first),0);
    tot:=0;
    l:=0;
    init;
    for i:=1 to l do
    begin
      fillchar(used,sizeof(used),true);
      find(i);
    end;
    ans:=0;
    for i:=1 to l do
      if link[i]<>0 then inc(ans);
    writeln(l-ans div 2)
  end;
end.