这个模型主要用来求连通块的数量,在求连通块时有“8连通”和“4连通”之分。
看上面的图形,如果是4连通那么红色和绿色就不连通(只有一个格子的“上下左右”相连才叫连通)。如果是8连通那就联通(不仅仅包含边相连,共顶点也叫连通)。
1097. 池塘计数 - AcWing题库
#include<iostream>
#include<utility>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
queue<PII> q;
const int N = 1010;
char g[N][N];
bool st[N][N];
int dx[8] = {-1,-1,0,1,1,1,0,-1};
int dy[8] = {0,1,1,1,0,-1,-1,-1};
int n,m,tmp=0;
void bfs(int sx,int sy){ //BFS模板
PII p = make_pair(sx,sy);
q.push(p);
st[sx][sy] = true; //首先,起点入队
while(!q.empty()){ //只要队列不空
PII v = q.front();
q.pop();
int ax = v.first;
int ay = v.second;
for(int i=0;i<8;i++){ //遍历与此时这个点相邻的点
int nx = ax+dx[i];
int ny = ay+dy[i];
if(st[nx][ny]) continue;
if(nx <1 || nx >n || ny <1 || ny >m) continue;
if(g[nx][ny]=='.') continue;
q.push(make_pair(nx,ny)); //入队
st[nx][ny] = true; //改变状态
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>g[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j]=='W' && !st[i][j]){
bfs(i,j);
tmp++;
}
}
}
cout<<tmp;
}
接下来讲一下一个比较难的题目(难在图的表示):
1 2 3 4 5 6 7
#############################
1 # | # | # | | #
#####---#####---#---#####---#
2 # # | # # # # #
#---#####---#####---#####---#
3 # | | # # # # #
#---#########---#####---#---#
4 # # | | | | # #
#############################
(图 1)
# = Wall
| = No wall
- = No wall
方向:上北下南左西右东。
图1是一个城堡的地形图。
请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。
城堡被分割成 nm个方格区域,每个方格区域可以有0~4面墙。
注意:墙体厚度忽略不计。
第一行包含两个整数 m 和 n,分别表示城堡南北方向的长度和东西方向的长度。
接下来 m 行,每行包含 n 个整数,每个整数都表示平面图对应位置的方块的墙的特征。
每个方块中墙的特征由数字 P 来描述,我们用1表示西墙,2表示北墙,4表示东墙,8表示南墙,PP 为该方块包含墙的数字之和。
例如,如果一个方块的 P 为3,则 3 = 1 + 2,该方块包含西墙和北墙。
城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。
输入的数据保证城堡至少有两个房间。
注意,这里面(1表示西墙,2表示北墙,4表示东墙,8表示南墙)
注意:我们得到的P是这些数字加起来的,因此,我们如果想看下一个位置通不通,只需要取相应位置的二进制数就可以了。比如:
现在一个方格的P是3(既1+2)我想看他的北面有没有墙。我们首先给这四个方向编一个号(西:0,北:1,东:2,南:3。这里可以用循环遍历四个方向!!)我们用P>>1,这是将P右移1位,这样原来的(3既0011)就变成001了然后我们再&1这样就可以得到最低位是0还是1了。
#include<iostream>
#include<queue>
#include<algorithm>
#include<utility>
using namespace std;
typedef pair<int,int> PII;
const int N = 55;
queue<PII> q;
int n,m,cnt,mara;
int g[N][N];
bool st[N][N];
int dx[] = {0,-1,0,1};
int dy[] = {-1,0,1,0};
int bfs(int sx,int sy){
q.push(make_pair(sx,sy));
st[sx][sy] = true;
int tem=1;//起点也算一个房间
while(!q.empty()){
PII p = q.front();
q.pop();
for(int i = 0; i<4 ;i++){
int nx = p.first + dx[i];
int ny = p.second + dy[i];
if(!st[nx][ny] && nx>=1 && nx<=n && ny>=1 && ny<=m && !(g[p.first][p.second]>>i&1)){//注意这里g[][]测试的是基点,而不是要遍历的点
q.push(make_pair(nx,ny));
st[nx][ny] = true;
tem++;
}
}
}
return tem;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>g[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!st[i][j]){
mara = max(bfs(i,j),mara);
cnt++;
}
}
}
cout<<cnt<<endl<<mara;
return 0;
}
1106. 山峰和山谷 - AcWing题库
#include<iostream>
#include<utility>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1010;
typedef pair<int,int> PII;
int g[N][N];
bool st[N][N];
int n,ah,al;
int dx[] = {-1,-1,0,1,1,1,0,-1};
int dy[] = {0,1,1,1,0,-1,-1,-1};
void bfs(int sx,int sy,bool &hashigher,bool &haslower){
queue<PII> q;
q.push(make_pair(sx,sy));
st[sx][sy] = true;
while(!q.empty()){
PII p = q.front();
q.pop();
for(int i=0;i<8;i++){
int nx = p.first + dx[i];
int ny = p.second + dy[i];
if(nx <1 || nx >n || ny <1 ||ny >n) continue;//超过界限的忽略
if(g[p.first][p.second]==g[nx][ny]){ //其周围的格子值,要么相等,要么不相等
if(!st[nx][ny]){ //没有被访问过,才能进行入队
q.push(make_pair(nx,ny));
st[nx][ny] = true;
}else continue;
}
else{ //格子值不相等
if(g[p.first][p.second] < g[nx][ny]) hashigher=true; //至少存在一个比这个高的。
else haslower=true; //至少存在一个比这个小的。
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>g[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(!st[i][j]){
bool hashigher=false,haslower=false;
bfs(i,j,hashigher,haslower);
if(hashigher && haslower) continue;//既有比它高的也有比它小的。
if(!hashigher) ah++; //如果没有比这个高的。那么这个最高。
if(!haslower) al++; //如果没有比这个小的,那么这个最小。
}
}
}
cout<<ah<<" "<<al<<endl;
return 0;
}
这个BFS设计的很灵活,从中可以理解到:如何进行BFS?关键步骤就是哪些入队列,哪些不入队列。这个题很巧妙,只有相等的才入队列,并将其状态设置位true。其他的不入队列,因此没有必要设置为true(如果设置了,反而会发生错误,导致后面遍历地图时自动略过这个点)。