Pascal usaco 城堡 题解

我们憨厚的USACO主人公农夫约翰(Farmer John)以无法想象的运气,在他生日那天收到了一份特别的礼物:一张“幸运爱尔兰”(一种彩票)。结果这张彩票让他获得了这次比赛唯一的奖品——坐落于爱尔兰郊外的一座梦幻般的城堡!

喜欢吹嘘的农夫约翰立刻回到有着吹嘘传统的威斯康辛老家开始吹嘘了, 农夫约翰想要告诉他的奶牛们关于他城堡的一切。他需要做一些吹嘘前的准备工作:比如说知道城堡有多少个房间,每个房间有多大。另外,农夫约翰想要把一面单独的墙(指两个单位间的墙)拆掉以形成一个更大的房间。 你的工作就是帮农夫约翰做以上的准备,算出房间数与房间的大小。

城堡的平面图被划分成M*N(1 <=M,N<=50)个正方形的单位,一个这样的单位可以有0到4面墙环绕。城堡周围一定有外墙环绕以遮风挡雨。(就是说平面图的四周一定是墙。)

请仔细研究下面这个有注解的城堡平面图:

这里写图片描述

友情提示,这个城堡的平面图是7×4个单位的。一个“房间”的是平面图中一个由“#”、“-”、“|”围成的格子(就是图里面的那一个个的格子)。比如说这个样例就有5个房间。(大小分别为9、7、3、1、8个单位(排名不分先后))

移去箭头所指的那面墙,可以使2个房间合为一个新房间,且比移去其他墙所形成的房间都大。(原文为:Removing the wall marked by the arrow merges a pair of rooms to make the largest possible room that can be made by removing a single wall. )

城堡保证至少有2个房间,而且一定有一面墙可以被移走。

输入输出格式
输入格式:
第一行有两个整数:M和N 城堡的平面图用一个由数字组成的矩阵表示,一个数字表示一个单位,矩阵有N行M列。输入与样例的图一致。

每一个单位的数字告诉我们这个单位的东西南北是否有墙存在。每个数字是由以下四个整数的某个或某几个或一个都没有加起来的。

1: 在西面有墙

扫描二维码关注公众号,回复: 3127572 查看本文章

2: 在北面有墙

4: 在东面有墙

8: 在南面有墙

城堡内部的墙会被规定两次。比如说(1,1)南面的墙,亦会被标记为(2,1)北面的墙。

输出格式:
输出包含如下4行:

第 1 行: 城堡的房间数目。

第 2 行: 最大的房间的大小

第 3 行: 移除一面墙能得到的最大的房间的大小

第 4 行: 移除哪面墙可以得到面积最大的新房间。

选择最佳的墙来推倒。有多解时选最靠西的,仍然有多解时选最靠南的。同一格子北边的墙比东边的墙更优先。

用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位(”N”(北)或者”E”(东))。

先用特殊处理将平面图还原,跟方便使用dfs
用dfs实现,枚举每个房间,求出最大面积,并保存,最后按题目要求求出最优解。
usaco城堡题解
以下为源代码:

const z:array[1..4,1..2]of -1..1=((0,-1),(-1,0),(0,1),(1,0));
      uu:array[1..4]of 1..4=(4,2,3,1);
var i,j,k,i1,j1,k1:longint;
    m,n,x,y,sum,int,int2,max:longint;
    a,b:array[-1..500,-1..500]of boolean;
    c,d:array[-1..500,-1..500]of longint;
    jz:array[0..100]of longint;
    u:array[0..10000]of longint;
    s:string;
    max_ch:longint;
    max_x,max_y:longint;
    sum2:longint;
    boo:array[1..4]of boolean;
procedure jz_(m:longint); //处理
begin
  jz[4]:=m div 8;
  m:=m mod 8;
  jz[3]:=m div 4;
  m:=m mod 4;
  jz[2]:=m div 2;
  m:=m mod 2;
  jz[1]:=m;
end;
procedure dfs_1(x,y:longint); //求出答案1,2
var i:longint;
begin
  if not b[x,y] then exit;
  b[x,y]:=false;
  if (x mod 2=1) and (y mod 2=1) then
  inc(int);
  for i:=1 to 4 do
  dfs_1(x+z[i,1],y+z[i,2]); //搜索
end;
procedure dfs_2(x,y:longint); //求出答案3
var i:longint;
begin
  if not b[x,y] then exit;
  b[x,y]:=false;
  c[x,y]:=u[int2];
  d[x,y]:=int2; //方便处理打洞位置
  for i:=1 to 4 do
  dfs_2(x+z[i,1],y+z[i,2]); //搜索
end;
begin
  read(m,n);
  s:='WNES';
  for i:=1 to n do
  for j:=1 to m do
  begin
    read(x);
    a[i*2-1,j*2-1]:=true;
    jz_(x);
    for k:=1 to 4 do
    begin
      if jz[k]=0 then
      a[i*2-1+z[k,1],j*2-1+z[k,2]]:=true;
    end;
  end;
  b:=a;
  {for i:=0 to n*2 do
  begin
    for j:=0 to m*2 do begin if not a[i,j] then write('#') else write(' '); end;
    writeln;
  end;}
  for i:=1 to n*2-1 do
  for j:=1 to m*2-1 do
  begin
    if b[i,j] then
    begin
    inc(int2);
    dfs_1(i,j);
    u[int2]:=int;
    if int>max then max:=int;
    int:=0;
    end;
  end;
  writeln(int2); // 房间数
  writeln(max); // 最大房间
  b:=a;
 { for i:=0 to n*2 do
  begin
    for j:=0 to m*2 do begin if not a[i,j] then write('#') else write(' '); end;
    writeln;
  end;
  writeln;}
  int2:=0;
  for i:=1 to n*2-1 do
  for j:=1 to m*2-1 do
  begin
    if b[i,j] then
    begin
    inc(int2);
    dfs_2(i,j);
    end;
  end;
  {for i:=0 to n*2 do
  begin
    for j:=0 to m*2 do write(c[i,j]);
    writeln;
  end;}
  max:=0;
  // 找到打洞处
  for j:=m downto 1 do
  for i:=1 to n do
  begin
    x:=i*2-1;
    y:=j*2-1;
    sum:=c[x,y];
    for i1:=3 downto 2 do
    begin
      if not a[x+z[i1,1],y+z[i1,2]] and (d[x+z[i1,1]*2,y+z[i1,2]*2]<>d[x,y]) then
      begin
      if (c[x+z[i1,1]*2,y+z[i1,2]*2]+sum>=max) then
      begin
      max:=c[x+z[i1,1]*2,y+z[i1,2]*2]+sum;
      for k1:=1 to 4 do boo[k1]:=false;
      max_x:=i;
      max_y:=j;
      max_ch:=i1;
      end;
      end;
    end;
  end;
  //
  writeln(max); // 打洞后最大房间
  writeln(max_x,' ',max_y,' ',s[max_ch]);
end.

声明:本人蒟蒻一枚。

猜你喜欢

转载自blog.csdn.net/sxy__orz/article/details/82468707