算法之搜索(备战蓝桥杯类似题型)

搜索分为DFS和BFS(深度优先搜索和广度优先搜索),dfs的基础题型可见排列组合问题,这篇文章主要记录一下遇到的几种连通块问题。
如果把深度优先搜索和广度优先搜索比作两个人的话,这两个人像性格迥异的双胞胎,哥哥DFS的性格很“执拗”,不撞南墙不回头,弟弟BFS的性格很沉稳,一步一步来hh

一、求细胞数量

题目描述

一矩形阵列由数字 0 0 0 9 9 9 组成,数字 1 1 1 9 9 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。

输入格式

第一行两个整数代表矩阵大小 n n n m m m

接下来 n n n 行,每行一个长度为 m m m 的只含字符 09 的字符串,代表这个 n × m n \times m n×m 的矩阵。

输出格式

一行一个整数代表细胞个数。

样例 #1

样例输入 #1

4 10
0234500067
1034560500
2045600671
0000000089

样例输出 #1

4

提示

数据规模与约定

对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m ≤ 100 1 \le n,m \le 100 1n,m100
——————————————————————————————
这个题用的DFS

#include
#include
#include
#include
using namespace std;
const int N=110;
int g[N][N];
int n,m;
int ans;
void dfs(int a,int b)
{
	if(a<1||a>n||b<1||b>m||g[a][b]==0)return ;//要有结束条件,不然死循环了
	g[a][b]=0;
	dfs(a-1,b);
	dfs(a+1,b);
	dfs(a,b-1);
	dfs(a,b+1);
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			char k;
			cin>>k;
			if(k!='0')g[i][j]=1;
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(g[i][j]==1)
			{
				ans++;
				dfs(i,j);
			}
		}
	}
	printf("%d",ans);
	return 0;
}

二、海战

题目背景

在峰会期间,武装部队得处于高度戒备。警察将监视每一条大街,军队将保卫建筑物,领空将布满了 F-2003 飞机。

此外,巡洋船只和舰队将被派去保护海岸线。不幸的是,因为种种原因,国防海军部仅有很少的几位军官能指挥大型海战。因此,他们培养了一些新海军指挥官。军官们选择了“海战”游戏来帮助他们学习。

题目描述

在一个方形的盘上,放置了固定数量和形状的船只,每只船却不能碰到其它的船。在本题中,我们认为船是方形的,所有的船只都是由图形组成的方形。

求出该棋盘上放置的船只的总数。

输入格式

第一行为两个整数 R R R C C C,用空格隔开,分别表示游戏棋盘的行数和列数。

接下来 R R R 行,每行 C C C 个字符,为 #.# 表示船只的一部分,. 表示水。

输出格式

一行一个字符串,如果船的位置放得正确(即棋盘上只存在相互之间不能接触的方形,如果两个 # 号上下相邻或左右相邻却分属两艘不同的船只,则称这两艘船相互接触了)。就输出 There are S ships. S S S 表示船只的数量。否则输出 Bad placement.

样例 #1

样例输入 #1

6 8
.....#.#
##.....#
##.....#
.......#
#......#
#..#...#

样例输出 #1

There are 5 ships.

提示

对于 100 % 100\% 100% 的数据, 1 ≤ R , C ≤ 1000 1 \le R,C \le 1000 1R,C1000
——————————————————————————————
此题和第一题几乎一样,但是要注意拐角处

#include
#include
#include
#include
using namespace std;
const int N=1100;
int g[N][N];
int n,m;
int ans;
void dfs(int a,int b)
{
	if(a<1||a>n||b<1||b>m||g[a][b]==0)return ;
	g[a][b]=0;
	dfs(a-1,b);
	dfs(a+1,b);
	dfs(a,b-1);
	dfs(a,b+1);
}
bool check(int x,int y)   //仅仅添加一个check函数
{
	int cnt=0;
	if(g[x][y]==1) cnt++;
	if(g[x+1][y]==1) cnt++;
	if(g[x][y+1]==1) cnt++;
	if(g[x+1][y+1]==1) cnt++;
	return cnt==3; 
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			char k;
			cin>>k;
			if(k!='.')g[i][j]=1;
		}
	}
	for(int i=1;i<n;i++)
	{
		for(int j=1;j<m;j++)
		{
			if(check(i,j))
			{
				printf("Bad placement.");
				return 0;
			}
			
			
		}
	}
		for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
		
			if(g[i][j]==1)
			{
				ans++;
				dfs(i,j);
			}
		}
	}
	printf("There are %d ships.",ans);
	return 0;
}

三、[蓝桥杯 2018 省 AB] 全球变暖

题目描述

你有一张某海域 N × N N \times N N×N 像素的照片,. 表示海洋、 # 表示陆地,如下所示:

.......
.##....
.##....
....##.
..####.
...###.
.......

其中 “上下左右” 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 2 2 座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:

.......
.......
.......
.......
....#..
.......
.......

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

输入格式

第一行包含一个整数 N N N ( 1 ≤ N ≤ 1000 ) (1 \le N \le 1000) (1N1000)

以下 N N N N N N 列代表一张海域照片。

照片保证第 1 1 1 行、第 1 1 1 列、第 N N N 行、第 N N N 列的像素都是海洋。

输出格式

一个整数表示答案。

样例 #1

样例输入 #1

7 
.......
.##....
.##....
....##.
..####.
...###.
.......

样例输出 #1

1

提示

时限 1 秒, 256M。蓝桥杯 2018 年第九届省赛
————————————————————————————
此题是蓝桥杯真题,此处用宽度优先搜索做一下

#include
#include
#include
#include
#include
using namespace std;
typedef pair<int,int> pii;
const int N=1010;
int n;
char g[N][N];
bool st[N][N];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
void bfs(int a,int b,int &total,int &bound){
	queue<pii> q;
	q.push({a,b});
	st[a][b]=true;
	while(!q.empty()){
		pii start=q.front();
		q.pop();
		total++;
		bool is_bound=false;
		for(int i=0;i<4;i++){
			int x=start.first+dx[i],y=start.second+dy[i];
			if(x<0||x>=n||y<0||y>=n)continue;
			if(st[x][y])continue;
			if(g[x][y]=='.'){
				is_bound=true;
				continue;
			}
			q.push({x,y});
			st[x][y]=true;
			
		}
		if(is_bound)bound++;
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%s",g[i]);
	}
	int cnt=0;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(!st[i][j]&&g[i][j]=='#'){
				int total=0,bound=0;
				bfs(i,j,total,bound);                                      
				if(total==bound)cnt++;
			}
		}
	}
	printf("%d",cnt);
	return 0;
}

谢谢~

你可能感兴趣的:(算法,蓝桥杯,深度优先)