【SSL】1104 &【洛谷】P1457城堡

【SSL】1104 &【洛谷】P1457城堡

Time Limit:1000MS
Memory Limit:65536K

Description

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

喜欢吹嘘的农夫约翰立刻回到有着吹嘘传统的威斯康辛老家开始吹嘘了, 农夫约翰想要告诉他的奶牛们关于他城堡的一切。他需要做一些吹嘘前的准备工作:比如说知道城堡有多少个房间,每个房间有多大。

另外,农夫约翰想要把一面单独的墙(指两个单位间的墙)拆掉以形成一个更大的房间。 你的工作就是帮农夫约翰做以上的准备,算出房间数与房间的大小。

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

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

在这里插入图片描述

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

移去箭头所指的那面墙,可以使 2 个房间合为一个新房间,且比移去其他墙所形成的房间都大。

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

Input

第一行两个正整数 m,n,表示城堡有 n 行 m 列。

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

1: 在西面有墙

2: 在北面有墙

4: 在东面有墙

8: 在南面有墙

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

Output

输出包含如下四行:

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

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

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

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

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

用该墙的南邻单位的北墙或西邻单位的东墙来表示这面墙,方法是输出邻近单位的行数、列数和墙的方位( 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

Hint

【数据范围】
对于 100% 的数据,1≤n,m≤50。

思路

先把状压拆出来。
用BFS求出前2问。
保存每个格子所在连通块的格子数。
枚举每个格子(注意枚举顺序)
如果上方有墙且与上方格子不属于同一个连通块且大于目前最大空间,更新,保持坐标。
如果右方有墙且与右方格子不属于同一个连通块且大于目前最大空间,更新,保持坐标。

代码

#include<iostream>
#include<cstdio>
#include<cstring> 
#include<queue>
#include<cmath>
using namespace std;
int n,m,x,y,zx,zy,ans,a[110][110],c[110][110],fs[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
bool q[4][110][110],d[110][110];
struct jgt
{
	int x,y;
};
jgt b[10010];
void input()
{
	int i,j,t;
	memset(q,0,sizeof(q));
	memset(d,true,sizeof(d));
	memset(a,0,sizeof(a));
	scanf("%d%d",&m,&n);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			scanf("%d",&t); 
			q[2][i][j]=!(t&1);//拆状压
			q[0][i][j]=!((t>>1)&1);
			q[3][i][j]=!((t>>2)&1);
			q[1][i][j]=!((t>>3)&1);
		}
	}
	return;
}
int BFS(int x,int y)
{
	int dx,dy,l,r,i;
	jgt t;
	d[x][y]=0;
	b[1].x=x;
	b[1].y=y;
	for(l=r=1;l<=r;l++)
	{
		for(i=0;i<4;i++)
		{
			dx=b[l].x+fs[i][0];
			dy=b[l].y+fs[i][1];
			if(q[i][b[l].x][b[l].y]&&1<=dx&&dx<=n&&1<=dy&&dy<=m&&d[dx][dy])
			{
				d[dx][dy]=0;
				b[++r].x=dx;
				b[r].y=dy;
			}
		}
	}
	for(l=1;l<=r;l++)
	{
		a[b[l].x][b[l].y]=r;
		c[b[l].x][b[l].y]=ans;
	}
	return r;
}
int main()
{
	int mx=0,i,j,ansx,ansy;
	char ansfs;
	input();
	ans=0;
	for(i=1;i<=n;i++)//计算前2问
		for(j=1;j<=m;j++)
			if(d[i][j])
			{
				ans++;
				mx=max(mx,BFS(i,j));
			}
	printf("%d\n%d\n",ans,mx);
	ans=0;
	for(j=1;j<=m;j++)//枚举每个格子
		for(i=n;i>=1;i--)
		{
			if((!q[0][i][j])&&c[i][j]!=c[i-1][j]&&a[i][j]+a[i-1][j]>ans&&i>=2)//条件
			{
				ans=a[i][j]+a[i-1][j];//更新
				ansx=i;
				ansy=j;
				ansfs='N';
			}
			if((!q[3][i][j])&&c[i][j]!=c[i][j+1]&&a[i][j]+a[i][j+1]>ans&&j<m)
			{
				ans=a[i][j]+a[i][j+1];
				ansx=i;
				ansy=j;
				ansfs='E';
			}
		}
	printf("%d\n%d %d %c",ans,ansx,ansy,ansfs);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值