二分图匹配程序总是很简单,这道题却做得很窝囊,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.