BFS 广(宽)度优先搜索题目推荐以及题解(3)

        噔噔噔哒!不得不说洛谷的题还不错,嘻嘻嘻,简单的还是挺简单的,今天我们练速度,讲四道题,大家放轻松,不难,基本上看一遍题目就能知道思路,就可以直接上手啦,尊嘟尊嘟。骗人的是小狗。

        话不多说,家人们进入状态吧。

        1.P1451 求细胞数量

        还是照常,先看题目:

        读懂题目后,其次就是输入输出样例,以及数据范围。已给出。

        思路分析:

        本蒟蒻看了又看洛谷里dalao们的题解,又用并查集啊,深度优先搜索啊什么的,虽然本蒟蒻也讲过相关文章,但本蒟蒻仅仅是一知半解[忏悔][忏悔],还有dalao说该题用BFS很难写,但本蒟蒻认为,只要在输入的图中稍微做一些修改的话,BFS还是最简单,最粗暴,最好理解的,(抛开编码长不说)。

        那么,我们又应该怎样操作呐?家人们也可以稍作思考。毕竟只有属于自己的思路,而且可行,那才是最好的。

        打个比方,就以上图中的输入样例来说:     

                0234500067

                1034560500

                2045600671

                0000000089

        由题可知,1到9都是表示细胞,哪为什么不能在输入这张图的时候给他一个通用的数字来表示细胞呢!?没错,我们就用万能的“1”来表示细胞。

        代码如下:

	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>mp[i][j];
			if(mp[i][j]>='1'&&mp[i][j]<='9')mp[i][j]='1';
		}
	}

       在输入的时候将表示细胞的1到9全部用1来代替。

        接下来就很简单了,就是很简单的连通性问题,求有多少个连通块。

        在前几篇文章中,我们也有讲过。

        传送门1:BFS 广(宽)度优先搜索题目推荐以及题解(2)_广度优先搜索洛谷习题-CSDN博客

        传送门2:BFS 广(宽)度优先搜索题目推荐以及题解(1)-CSDN博客

         话不多说,上AC代码:

#include<iostream>
#include<queue>
using namespace std;
struct node{
	int x,y;
};
char mp[103][103];
bool vis[103][103];
int n,m,ans=0;
int dx[]={-1,0,1,0};		//上左下右
int dy[]={0,-1,0,1};		//上左下右
void bfs(int x,int y){
	queue<node> q;
	node fron,now;
	fron.x=x; fron.y=y;
	q.push(fron);
	while(!q.empty()){
		fron=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			now.x=fron.x+dx[i];
			now.y=fron.y+dy[i];
			if(vis[now.x][now.y]||mp[now.x][now.y]=='0')continue;
			if(now.x<1||now.y<1||now.x>n||now.y>m)continue;
			vis[now.x][now.y]=true;
			q.push(now);
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>mp[i][j];
			if(mp[i][j]>='1'&&mp[i][j]<='9')mp[i][j]='1';
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(!vis[i][j]&&mp[i][j]=='1'){
				bfs(i,j);
				ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}

        一共48行,不多不少,刚刚好。

        2.P1699 [USACO19OPEN]  Bucket Brigade B

        这道题也不难,相当于给定起点和终点,接着求出两点之间的最短路径而已,权值为1,但需要注意的是:在输出的最短路径中要减1,方才是正确答案。这个我们读样例便可以知道,我就不多阐述了。

        具体思路也和上一段中所说的八九不离十,我们就直接上AC代码了:

#include<iostream>
#include<queue>
using namespace std;
struct node{
	int x,y,step=0;
};
char mp[11][11];
bool vis[11][11];
int dx[]={-1,0,1,0};		//上左下右
int dy[]={0,-1,0,1};		//上左下右
void bfs(int x,int y){
	node fron,now;
	fron.x=x; fron.y=y;
	queue<node> q;
	q.push(fron);
	vis[x][y]=true;
	while(!q.empty()){
		fron=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			now.x=fron.x+dx[i];
			now.y=fron.y+dy[i];
			if(vis[now.x][now.y])continue;
			if(mp[now.x][now.y]=='R')continue;
			if(now.x<1||now.y<1)continue;
			if(now.x>10||now.y>10)continue;
			vis[now.x][now.y]=true;
			now.step=fron.step+1;
			if(mp[now.x][now.y]=='L'){
				cout<<now.step-1;
				return ;
			}
			q.push(now);
		}
	}
}
int main(){
	int x,y;
	for(int i=1;i<=10;i++){
		for(int j=1;j<=10;j++){
			cin>>mp[i][j];
			if(mp[i][j]=='B'){
				x=i; y=j;
			}
		}
	}
	bfs(x,y);
	return 0;
}

        一共49行。但在洛谷的题解中,我竟然看到了一个特别优秀的做法,在着本蒟蒻就分析一下。

        首先重回题目,只有一个起点,终点,石头,那也就是说:答案就是起点和终点的哈夫曼距离-1!!!也许会有家人说那如果路途中有石头怎么办,很简单,答案直接就是起点和终点的哈夫曼距离+1!!!这不就直接AC掉了吗!?蛙趣,“中州果然藏龙卧虎”。

        代码的话,由于这个思路简单,家人们就自己写吧,锻炼一下,实在不行也可以问。

        3.P1746 离开中山路

        本题思路和上一道一致,家人们思考完,可以直接看代码了。

        我先在这空几行,免得家人们直接看到答案,惹得分心。

                嘻嘻嘻。

                6,5,4,

                3,2,1.

        好啦,不闹了,上AC代码:

#include<iostream>
#include<queue>
using namespace std;
struct node{
	int x,y,step=0;
};
int x,y,x2,y2,n;
int dx[]={-1,0,1,0};		//上左下右
int dy[]={0,-1,0,1};		//上左下右
char mp[1010][1010];
bool vis[1001][1001];
void bfs(){
	node fron,now;
	fron.x=x; fron.y=y;
	vis[x][y]=true;
	queue<node> q;
	q.push(fron);
	while(!q.empty()){
		fron=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			now.x=fron.x+dx[i];
			now.y=fron.y+dy[i];
			if(vis[now.x][now.y])continue;
			if(mp[now.x][now.y]=='1')continue;
			if(now.x<1||now.y<1)continue;
			if(now.x>n||now.y>n)continue;
			vis[now.x][now.y]=true;
			now.step=fron.step+1;
			if(now.x==x2&&now.y==y2){
				cout<<now.step;
				return;
			}
			q.push(now);
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>mp[i][j];
		}
	}
	cin>>x>>y>>x2>>y2;
	bfs();
	return 0;
}

        一共还是48行。

        4.P8662 [蓝桥杯 2018 省 AB] 全球变暖

        这题,不得不说还是有点东西的,本尊提交了4次才通过[捂脸][忏悔]。

        这题的描述有忆(没打错字,就是记忆的忆)丢丢长。接下来是输入输出样例,以及数据范围。

        话说这蓝桥杯有点实力啊,今年竟然昨天才发通知报名。。。

        这题又该怎么做呢,家人们可以先思考片刻。

        思路分析:

        其实这道题,我们可以看成是连通性问题的变式题,是的,我们可以用连通性问题的思路,虽然洛谷的题解中的daolao们不是这么干的,他们大多都用DFS,只有本蒟蒻用BFS,qwq。

        我们先搜索所有的连通块,再判断这个连通块是否被完全淹没,用bool类型的flag判断。那么又要怎么判断呐?我们先看图,如果这个连通块中有一部分的上面,下面,左边,右边,都是'#'的话,那么这个连通块就不算是完全淹没。我们就可以利用这个来判断。

        我们先按这个思路写出代码:

#include<iostream>
#include<queue>
using namespace std;
struct node{
	int x,y;
};
int n,ans=0;
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
char mp[1010][1010];
bool vis[1010][1010];
bool check(node a){
	for(int i=0;i<4;i++){
		node now;
		now.x=a.x+dx[i];
		now.y=a.y+dy[i];
		if(mp[now.x][now.y]=='.')return false;
	}
	return true;
}
bool flag=false;
void bfs(int x,int y){
	node fron,now;
	fron.x=x; fron.y=y;
	queue<node> q;
	q.push(fron);
	vis[x][y]=true;
	while(!q.empty()){
		fron=q.front();
		q.pop();
		if(check(fron)){
			flag=true;
            return ;
		}
		for(int i=0;i<4;i++){
			now.x=fron.x+dx[i];
			now.y=fron.y+dy[i];
			if(mp[now.x][now.y]=='.')continue;
			if(vis[now.x][now.y])continue;
			if(now.x<1||now.y<1)continue;
			if(now.x>n||now.y>n)continue;
			vis[now.x][now.y]=true;
			q.push(now);
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>mp[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			flag=false;
			if(!vis[i][j]&&mp[i][j]=='#'){
				bfs(i,j);
				if(!flag)ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}

        但当我们提交后就会发现,咦?怎么只有12pts???

        不要问我为什么,我一开始就是这样的。。。

        家人们可以思考一下原因。

        好啦,不卖关子了,原因就是bfs中的return。。。那为什么return会有问题呢?

        原因就是,在连通块中只要有一个部分的上面,下面,左边,右边,都是'#'的话,那么这个连通块就不算是完全淹没。但,因为这是一整个连通块,如果我们搜索到了这个连通块是否完全淹没后就return的话,那么在这个连通块中,还没搜索的部分,将会被当作新的连通块再次搜索,这就会导致重复。

        所以,正确的代码,应该是这样的:

#include<iostream>
#include<queue>
using namespace std;
struct node{
	int x,y;
};
int n,ans=0;
int dx[]={-1,0,1,0};
int dy[]={0,-1,0,1};
char mp[1010][1010];
bool vis[1010][1010];
bool check(node a){
	for(int i=0;i<4;i++){
		node now;
		now.x=a.x+dx[i];
		now.y=a.y+dy[i];
		if(mp[now.x][now.y]=='.')return false;
	}
	return true;
}
bool flag=false;
void bfs(int x,int y){
	node fron,now;
	fron.x=x; fron.y=y;
	queue<node> q;
	q.push(fron);
	vis[x][y]=true;
	while(!q.empty()){
		fron=q.front();
		q.pop();
		if(check(fron)){
			flag=true;
		}
		for(int i=0;i<4;i++){
			now.x=fron.x+dx[i];
			now.y=fron.y+dy[i];
			if(mp[now.x][now.y]=='.')continue;
			if(vis[now.x][now.y])continue;
			if(now.x<1||now.y<1)continue;
			if(now.x>n||now.y>n)continue;
			vis[now.x][now.y]=true;
			q.push(now);
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>mp[i][j];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			flag=false;
			if(!vis[i][j]&&mp[i][j]=='#'){
				bfs(i,j);
				if(!flag)ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}

        好啦,四题,刚刚好。

        本篇就先将到这啦。感谢家人们的支持,你们的鼓励就是我最大的动力。

        最后的最后,祝大家在蓝桥杯和csp-j/s中旗开得胜,嘻嘻嘻。

(侵删)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值