1. 程式人生 > 其它 >【SSL】1104 &【洛谷】P1457城堡

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

技術標籤:BFS

【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;
}