题目大意:
有T个不同的M*N的农场,每个农场很多草地,墙,空地,农夫想在空地上放置机器人,对于一个机器人,能向它的四周攻击,直到碰到墙或出界,问最多能放置多少个机器人。
T <= 11
1<= m, n <=50
题解:
这题其实很简单的...
我们可以可以用到二分图匹配,
首先我们可以自行的去构建很多个独立的行,即每一行被障碍分成了很多个小块,把这些小块给标记
然后继续构建很多个独立的列,同理。
然后我们要求的就是这些独立行与独立列构成的连边的二分图的最大匹配,因为每匹配到一条边,其实就等价于加入了一个点到图中。
这时最大放置数就是最大匹配数。
代码:
const
maxn=2500;
var
map:Array [0..maxn+1,0..maxn+1] of boolean;
cover:array [0..maxn+1] of boolean;
link:array [0..maxn+1] of longint;
c,d:array [0..51,0..51] of longint;
e:array [0..51,0..51] of boolean;
a:array [0..51,0..51] of char;
t,ans,i,j,k,n,m,cp,op:longint;
function find(x:longint):boolean;
var
q,i:longint;
begin
for i:=1 to op do
if map[x,i] and not(cover[i]) then
begin
q:=link[i];
link[i]:=x;
cover[i]:=true;
if (q=0) or find(q) then exit(true);
link[i]:=q;
end;
exit(false);
end;
procedure work(x,y:longint);
var
i:longint;
check:boolean;
begin
check:=true;
if y=1 then
begin
for i:=1 to m do
if a[x,i]='o'
then begin
if check then
begin
inc(cp);
check:=false;
end;
c[x,i]:=cp;
end
else if a[x,i]='#' then check:=true;
end else
begin
for i:=1 to n do
if a[i,x]='o'
then begin
if check then
begin
inc(op);
check:=false;
end;
d[i,x]:=op;
end
else if a[i,x]='#' then check:=true;
end;
end;
begin
readln(t);
k:=t;
while t>=1 do
begin
fillchar(map,sizeof(map),false);
fillchar(link,sizeof(link),0);
fillchar(e,sizeof(e),false);
fillchar(c,sizeof(c),0);
fillchar(d,sizeof(d),0);
writeln('Case :',k-t+1);
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do read(a[i,j]);
readln;
end;
ans:=0;
cp:=0;
op:=0;
for i:=1 to n do
begin
a[i,0]:='#';
work(i,1);
end;
for i:=1 to m do
begin
a[0,i]:='#';
work(i,2);
end;
for i:=1 to n do
for j:=1 to m do
if a[i,j]='o' then
map[c[i,j],d[i,j]]:=true;
for i:=1 to cp do
begin
fillchar(cover,sizeof(cover),false);
if find(i) then inc(ans);
end;
writeln(ans);
dec(t);
end;
end.