火力网加强版(difficult) SSL_1124 (最大匹配)

Description

  假定我们有一个正方形的城市,拥有笔直的街道。城市由n行n列正方形的地块组成,每一块表示为一个街道或一堵墙。
  碉堡就是一个小的城堡,有四个用于射击的口子。这四个口子分别朝着东、南、西、北方向。每一个口子都有一个用于射击的机关枪。
  我们假定子弹力量很大,足以射到任何距离,并且破坏线路上的碉堡。另一方面,一堵墙非常牢固可以挡住子弹。
  我们的目标就是在城市上放置一些碉堡,使得没有两个碉堡可以互相破坏。碉堡的合法配置就是没有两个碉堡在同一行或同一列上,除非它们之间至少有一堵墙隔在中间。在题目中我们考虑小的正方形城市(最多4×4)包含墙,使得子弹不能穿越。
  下面的图示表示同一个区域,第一个图为空图,第二个和第三个图表示合法的配置,第四个图和第五个图表示违法的配置。对这个区域而言,合法配置的最大的碉堡的数量为5,第二个图显示了一种配置的方法,但还有另外的方法。

  你的任务就是编程,对于给出的地图,计算碉堡的最大数量,可以合法配置在城市中。

Input

  输入的第一行为n表示一个地图的大小,n最多为10,下面n行表示地图的每一列,一个‘.’表示空地,‘X’表示墙。
  

Output

输出一个最大的碉堡数量,使得在城市中可以合法配置。

Sample Input

4
.X..
….
XX..
….
Sample Output

5

var
 i,n,m,j,k,tot:longint;
 map:array[0..256,0..256] of boolean;
 e:array[0..256,0..256,1..2] of longint;
 b:array[0..12] of longint;
 cover:array[0..256] of boolean;
 link,ans:array[0..256] of longint;
procedure test(a,b,c,d,f:longint);
 var
 i:longint;
begin
 if d=1 then
  for i:=a to b do
   e[c,i,d]:=f;
 if d=2 then
  for i:=a to b do
   e[i,c,d]:=f;
end;



function find(i,x:longint):boolean;
 var
 k,q:longint;
begin
 find:=true;
 for k:=1 to x do
  if map[i,k] and not(cover[k]) then
   begin
    q:=link[k]; link[k]:=i; cover[k]:=true;
    if (q=0) or (find(q,x)) then exit;
    link[k]:=q;
   end;
  find:=false;
end;

procedure main(x:longint);
 var
 i:longint;
begin
 for i:=1 to x do
  begin
   fillchar(cover,sizeof(cover),false);
    find(i,x);
  end;
end;

procedure print(x,a:longint);
 var
 i,s:longint;
begin
 s:=0;
 for i:=1 to x do
  if link[i]<>0 then inc(s);
 writeln(s);
end;

procedure init(x,y:longint);
 var
 n,m,i,j:longint;
 check:array[0..51,0..51] of boolean;
 a:array[0..51,0..51] of char;
 c,d,tot,ff,f,max:longint;
begin
 n:=y;
 b[x]:=n;
 fillchar(check,sizeof(check),false);
 fillchar(e,sizeof(e),0);
 fillchar(a,sizeof(a),'0');
 c:=0;
 tot:=0;
 m:=n;
 for i:=1 to n do
 begin
  for j:=1 to m do
  begin
   read(a[i,j]);
   if a[i,j]='.' then check[i,j]:=true;
  end;
  readln;
 end;
 for i:=1 to n+1 do
  for j:=1 to m+1 do
  begin
   if (c=0) and (a[i,j]='.') then begin
                                   c:=j; inc(tot);
                                   end;
   if not(check[i,j]) then
    if c<>0 then
     begin
      test(c,j-1,i,1,tot);
      c:=0;
     end;
  end;
 c:=0;
 ff:=tot;
 tot:=0;
 for i:=1 to m+1 do
  for j:=1 to n+1 do
   begin
    if (c=0) and (a[j,i]='.') then begin
                                  c:=j; inc(tot);
                                  end;
    if not(check[j,i]) then
     if c<>0 then
      begin
       test(c,j-1,i,2,tot);
       c:=0;
      end;
   end;
  f:=tot;
 fillchar(map,sizeof(map),0);
 fillchar(link,sizeof(link),0);
 for i:=1 to n do
  for j:=1 to m do
   if (e[i,j,1]<>0) and (e[i,j,2]<>0) then map[e[i,j,1],e[i,j,2]]:=true;
  if ff>f then max:=ff
          else max:=f;
 main(max);
 print(max,x);
end;

begin
 readln(n);
 if n<>0 then init(i,n);
end.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值