城堡问题(DFS)

城堡问题

题目描述

     1   2   3   4   5   6   7  
   #############################
 1 #   |   #   |   #   |   |   #
   #####---#####---#---#####---#
 2 #   #   |   #   #   #   #   #
   #---#####---#####---#####---#
 3 #   |   |   #   #   #   #   #
   #---#########---#####---#---#
 4 #   #   |   |   |   |   #   #
   #############################

   #  = Wall   
   |  = No wall
   -  = No wall

   方向:上北下南左西右东。

上图是一个城堡的地形图。

城堡被分割成 m×n 个方格区域,每个方格区域可以有 0∼4 面墙。

请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。

注意:墙体厚度忽略不计,输入数据保证存在最外层的一圈墙。

输入格式

第一行包含两个整数 m 和 n,分别表示城堡南北方向的长度和东西方向的长度。

接下来 m 行,每行包含 n 个整数,每个整数都表示平面图对应位置的方块的墙的特征。

每个方块中墙的特征由数字 P 来描述,我们用 1 表示西墙,2 表示北墙,4 表示东墙,8 表示南墙,P 为该方块包含墙的数字之和。

例如,如果一个方块的 P 为 3,则 3=1+2,该方块包含西墙和北墙。

城堡的内墙被计算两次,方块 (1,1) 的南墙同时也是方块 (2,1) 的北墙。

输入的数据保证城堡至少有两个房间,且城堡最外圈一定有墙。

输出格式

共两行,第一行输出房间总数,第二行输出最大房间的面积(方块数)。

输入输出样例

输入#1

4 7 
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

输出#1:

5
9

数据范围

对于 100% 的数据,保证 1≤m,n≤50,0≤P≤15。

提示

样例中的城堡如下图所示: 

大体思路

先将在每个方向开墙的对应的数值算出,我们可以创立一个三维数组,前两位用来存储对应房间的坐标,后一位表示当前格子的墙的状态(1,2,3,4各代表一个方向有墙),再进行基本的dfs步骤就可以了。

代码奉上

#include "bits/stdc++.h"
using namespace std;
const int N = 60 + 8;
int m, n, room, step, maxn;
int xx[5] = {0,0,1,0,-1}, yy[5] = {0,1,0,-1,0};
int a[N][N], c[N][N][8];
bool vis[N][N]; //用一个bool类型的数组判断哪些格子已经走过了
void dfs(int x, int y) {
	maxn = max(step,maxn); //比较房间的大小,并更新
	for(int i=1; i<=4; i++) { //深搜核心步骤 
		int dx = x + xx[i],dy = y + yy[i];
		if(dx < 1 || dx > n || dy < 1 || dy > m) continue; //判断是否跃出格子的边界
		if(c[x][y][i] == 0 && vis[dx][dy] == false) { //判断格子是否走过
			vis[dx][dy] = true; //将已走过的格子标记
			step++; //刷新房间大小
			dfs(dx,dy);
		}
	}
	return ;
}

int main() {
	cin>>n>>m;
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			cin>>a[i][j]; //输入格子的数,并判断每个格子在各个方向的墙的状态
			if(a[i][j] == 4||a[i][j] == 5||
			a[i][j] == 6||a[i][j] == 7||
			a[i][j] == 12||a[i][j] == 13||
			a[i][j] == 14||a[i][j] == 15) {
				c[i][j][1]++;
			}
			if(a[i][j] == 8||a[i][j] == 9||
			a[i][j] == 10||a[i][j] == 11||
			a[i][j] == 12||a[i][j] == 13||
			a[i][j] == 14||a[i][j] == 15) {
				c[i][j][2]++;
			}
			if(a[i][j] == 1||a[i][j] == 3||
			a[i][j] == 5||a[i][j] == 7||
			a[i][j] == 9||a[i][j] == 11||
			a[i][j] == 13||a[i][j] == 15) {
				c[i][j][3]++;
			}
			if(a[i][j] == 2||a[i][j] == 3||
			a[i][j] == 6||a[i][j] == 7||
			a[i][j] == 10||a[i][j] == 11||
			a[i][j] == 14||a[i][j] == 15) {
				c[i][j][4]++;
			}
		}
	}
	//判断完成后进入dfs 
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=m; j++) {
			if(vis[i][j] == false) {
				step = 1; //将每一个房间的大小初始化为1格
				vis[i][j] = true; //将已走过的格子标记
				dfs(i,j);
				room++; //储存房间数 
			}
		}
	}
	cout<<room<<endl<<maxn; //输出 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值