1817:城堡问题
P.S.如果有需要英文版的同学轻点英文版,需要源代码的同学轻点源代码。
总时间限制: 1000ms 内存限制: 65536kB
描述
1 2 3 4 5 6 7
#############################
1 # | # | # | | #
#####---#####---#---#####---#
2 # # | # # # # #
#---#####---#####---#####---#
3 # | | # # # # #
#---#########---#####---#---#
4 # # | | | | # #
#############################
(图 1)
# = Wall
| = No wall
- = No wall
图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成mn(m≤50,n≤50)个方块,每个方块可以有0~4面墙。
输入
程序从标准输入设备读入数据。第一行是两个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0≤p≤50)描述。用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,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
样例输出
5
9
来源
1164
【代码】
状态: Accepted
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int m,n,ans,cnt,bigest;
bool flag[100][100],q[100][100][4];
int map[105][105];
int wayr[4]={0,1,0,-1},wayc[4]={1,0,-1,0};
bool check(int a,int b,int x)
{
if(a<m&&b<n&&a>=0&&b>=0&&q[a][b][x]&&!flag[a][b]) return 1;
return 0;
}
void dfs(int y,int c) //似于递归
{
for(int i=0;i<4;i++)//四种走法
if(check(y+wayr[i],c+wayc[i],i))
{
flag[y+wayr[i]][c+wayc[i]]=1;
cnt++; //如果走得通,房间数+1,且标记
dfs(y+wayr[i],c+wayc[i]);
} //不断递归,到最后cnt就为最大房间数
}
int main()
{
scanf("%d%d",&m,&n);
for(int l=0;l<m;l++)
for(int j=0;j<n;j++)
{
scanf("%d",&map[l][j]);
if(!(map[l][j]&1)) q[l][j][0]=1; //判断走不走得通
if(!(map[l][j]&2)) q[l][j][1]=1; //也是有没有墙
if(!(map[l][j]&4)) q[l][j][2]=1; //i行j列的方块,0表示西墙,1表示北墙,2表示东墙,3表示南墙。
if(!(map[l][j]&8)) q[l][j][3]=1;
}
for(int l=0;l<m;l++)
for(int j=0;j<n;j++)
if(!flag[l][j]) //判断走没走过
{
flag[l][j]=1; //标记
cnt=1;//房间的包括的方块数(初始都为1),每个房间至少有一个
dfs(l,j);
if(cnt>bigest) bigest=cnt; //找到最大房间包括的方块数
ans++; // 房间数
}
printf("%d\n%d\n",ans,bigest);
}
拓展:
同学们知道为什么要写这些东西吗:
if(!(map[l][j]&1)) q[l][j][0]=1;
if(!(map[l][j]&2)) q[l][j][1]=1;
if(!(map[l][j]&4)) q[l][j][2]=1;
if(!(map[l][j]&8)) q[l][j][3]=1;
首先,取反(!)说明的是:1代表不行,0表示可以,在这里,同学们需要注意。那有些同学又有疑问了:为什么在check函数里判断的时候不加(!)?
bool check(int a,int b,int x)
{
if(a<m&&b<n&&a>=0&&b>=0&&q[a][b][x]&&!flag[a][b]) return 1;
return 0;
}
同学们可以仔细看一下check的运用:
if(check(y+wayr[i],c+wayc[i],i))
在这里我们可以知道,check是用来判断能不能走的,也就是用于计算在房间里有多少个方块的。能走得通,自然不能有墙。
回归正题:为什么要写那些东西?
此关系到二进制。首先同学们要知道1、2、4、8用二进制怎么表示?二进制变化如下:
1->0001 2->0010 4->0100 8->1000
【精英必知】
1、2的0次方为1 ---> 即0001
2、2的1次方为2 ---> 即0010
3、2的2次方为4 ---> 即0100
4、2的3次方为8 ---> 即1000
......
综上,第n个为:2的(n-1)次方。
通过上面,同学们可以观察到1、2、4、8转换为2进制后,可以很好的辨析出是否相等。
e.g:给你一个28,你能判断它有哪些墙了吗?
首先28转换为2进制后为:11100
可以对比一下: 0001(1)
0010(2)
0100(4)
1000(8)
p.s:用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。
同学们可以很清楚的看出28有:东墙、南墙。
所以同学们现在应该清楚了。
if(!(map[l][j]&1)) q[l][j][0]=1;
if(!(map[l][j]&2)) q[l][j][1]=1;
if(!(map[l][j]&4)) q[l][j][2]=1;
if(!(map[l][j]&8)) q[l][j][3]=1;
【意思】找是不是没有西墙、北墙、东墙、南墙。
p.s.同学们喜欢的话可以加关注,顶一个。Tanks!