描述
我们憨厚的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: 第一行有两个整数:M和N 城堡的平面图用一个由数字组成的矩阵表示,一个数字表示一个单位,矩阵有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
由于数据很小,所以求出房间数目后直接枚举每一个点的北墙和东墙即可。
样例还是很全面的,刚开始没考虑墙的两边是一个房间,样例都过不了。。。
/* ID: your_id_here PROG: castle LANG: C++ */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int dr[]={0,-1,0,1},dc[]={-1,0,1,0}; int n,m,mp[55][55],mark[55][55],num,siz[2501],tmp,maxsiz,tr,tc,sum; inline bool isLegal(int r,int c) {//判断坐标是否在城堡内 return 0<=r&&r<n&&0<=c&&c<m; } void dfs(int r,int c) { mark[r][c]=num,++tmp; for(int i=0;i<4;++i) if((mp[r][c]&(1<<i))==0&&isLegal(tr=r+dr[i],tc=c+dc[i])&&mark[tr][tc]==0)//与相邻的房间没有墙且其未被参观过则递归 dfs(tr,tc); } int main() { int i,j,ansr,ansc; char dir; freopen("castle.in","r",stdin); freopen("castle.out","w",stdout); while(2==scanf("%d%d",&m,&n)) { for(i=0;i<n;++i) for(j=0;j<m;++j) scanf("%d",&mp[i][j]); memset(mark,0,sizeof(mark)); for(num=1,maxsiz=i=0;i<n;++i) for(j=0;j<m;++j) if(mark[i][j]==0) { tmp=0; dfs(i,j);//Flood Fill if(maxsiz<(siz[num++]=tmp)) maxsiz=tmp; } for(sum=0,j=0;j<m;++j)//由于是输出最西(先)、最东(后)的房间坐标,所以列递增(后),行递减(先) for(i=n-1;i>=0;--i) { if((mp[i][j]&2)&&isLegal(tr=i-1,j)&&mark[i][j]!=mark[tr][j]&&sum<(tmp=siz[mark[i][j]]+siz[mark[tr][j]])) sum=tmp,ansr=i,ansc=j,dir='N';//两个房间编号不同时能打通墙,北墙先 if((mp[i][j]&4)&&isLegal(i,tc=j+1)&&mark[i][j]!=mark[i][tc]&&sum<(tmp=siz[mark[i][j]]+siz[mark[i][tc]])) sum=tmp,ansr=i,ansc=j,dir='E';//东墙后 } printf("%d\n%d\n%d\n%d %d %c\n",num-1,maxsiz,sum,ansr+1,ansc+1,dir); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。