【搜索】【usaco 2.1.1】castle

问题

描述

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

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

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

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

    1   2   3   4   5   6   7
  #############################
1 #   |   #   |   #   |   |   #
  #####---#####---#---#####---#   
2 #   #   |   #   #   #   #   #
  #---#####---#####---#####---#
3 #   |   |   #   #   #   #   #   
  #---#########---#####---#---#
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个房间,而且一定有一面墙可以被移走。

格式

PROGRAM NAME: castle

INPUT FORMAT: 城堡的平面图用一个由数字组成的矩阵表示,一个数字表示一个单位,矩阵有N行M列。输入与样例的图一致。

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

1: 在西面有墙
2: 在北面有墙
4: 在东面有墙
8: 在南面有墙

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

OUTPUT FORMAT:

(file castle.out)

输出包含如下4行:

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

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

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

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

选择最佳的墙来推倒。有多解时选(重心)最靠西的(仍然有多解时选这些里面(重心)最靠南的)。 用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位("N"(北)或者"E"(东))。

SAMPLE INPUT

7 4
11 6 11 6 3 10 6
7 9 6 13 5 15 5
1 10 12 7 13 7 5
13 11 10 8 10 12 13

SAMPLE OUTPUT

5
9
16
4 1 E
分析
显然要用到搜索,像这一类求“房间”的题,floodfill是个很好的方法。我们要处理几个问题
1、读入数据,我们知道每个数只能选择加或不加,即每个点的一个方向或有墙,或没有墙。我们从大到小(不能颠倒)来做,如果比当前加数大,
我们就认为在该面有墙,并减去这个值。我们开一个3维数组wall[i,j,1..4]纪录该点的四个方向是否有墙。
2、我们对每点floodfill产生房间,并找到最大的面积。
3、枚举拆掉每面墙,注意这里的循环顺序是唯一确定的(题目要求)。如果该墙两侧的点不属于一个房间,我们就拆除中间的墙。
注意定义的方向必须完全对应。开数组的时候要多开,因为这是个重新构图的过程,可能超过给定的值。
反思
floodfill的应用要熟练掌握。对数据的预处理技巧也很巧妙。合适的状态表示,有利于搜索。注意题目要求
总之,这道题很好
code
{
ID:lxf98092
PROB:castle
LANG:PASCAL
}
program liukee;
var
  d:array[1..4,1..2] of longint=((-1,0),(1,0),(0,-1),(0,1));
  wall:array[0..100,0..100,1..4] of boolean;
  room:array[0..100,0..100] of longint;
  s:array[0..2500] of longint;
  xx,yy,i,j,color,m,n,max:longint;
  ch:char;

procedure init;
var
  i,j:longint;
  x:longint;
begin
  readln(m,n);
  for i:=1 to n do
  begin
    for j:=1 to m do
	begin
	  read(x);
	  if x>=8 then begin dec(x,8);wall[i,j,2]:=true;end;
	  if x>=4 then begin dec(x,4);wall[i,j,4]:=true;end;
	  if x>=2 then begin dec(x,2);wall[i,j,1]:=true;end;
	  if x>=1 then begin dec(x,1);wall[i,j,3]:=true;end;
	end;
	readln;
  end;
end;


procedure floodfill(x,y:longint);
var
  i,j:longint;
begin
  if room[x,y]<>0 then exit;
  if(x>n)or(y>m)or(x<1)or(y<1)then exit;
  room[x,y]:=color;
  inc(s[color]);
  for i:=1 to 4 do
    if not(wall[x,y,i]) then floodfill(x+d[i,1],y+d[i,2]);
end;

begin
  assign(input,'castle.in');
  reset(input);
  assign(output,'castle.out');
  rewrite(output);
  init;
  for i:=1 to n do
    for j:=1 to m do
	  if room[i,j]=0 then
	  begin
	    inc(color);
		floodfill(i,j);
	  end;
  writeln(color);
  max:=0;
  for i:=1 to color do
    if s[i]>max then max:=s[i];
  writeln(max);
  max:=0;
  for j:=1 to m do
    for i:=n downto 1 do
	begin
	  if wall[i,j,1] then
	    if (room[i,j]<>room[i-1,j])and(s[room[i,j]]+s[room[i-1,j]]>max)then
		begin
		  max:=s[room[i,j]]+s[room[i-1,j]];
		  xx:=i;
		  yy:=j;
		  ch:='N'
		end;
	  if wall[i,j,4] then
	    if (room[i,j]<>room[i,j+1])and(s[room[i,j]]+s[room[i,j+1]]>max)then
		begin
		  max:=s[room[i,j]]+s[room[i,j+1]];
		  xx:=i;
		  yy:=j;
		  ch:='E';
		end;
    end;
  writeln(max);
  writeln(xx,' ',yy,' ',ch);
  close(input);
  close(output);
end.

	


posted @ 2010-11-12 16:47  liukee  阅读(262)  评论(0编辑  收藏  举报