广度优先搜索

例1 洛谷P1451 细胞

1.注意边界(0或1的差别)

2.输入m*n矩阵时 因为从1开始 所以必须c[i]+1以确保能读到第一列数

3.注意是从head位置开始向四个方向搜索,所以不是kx=x+xx[i],而是kx=a[head].x+xx[i]

4.运用队列 从上到下 从左到右寻找细胞 令找到的细胞入队并标记为'0'

【代码】

#include <bits/stdc++.h>
using namespace std;
char c[1005][1005];
struct s{
	int x,y;
}a[1000005];
int n,m;
int head,tail,ans;//定义首尾指针 
int xx[4]={-1,0,1,0};
int yy[4]={0,1,0,-1};//偏置数组 
void bfs(int x,int y){
	int kx,ky;
	head=1,tail=2;//赋初值 
	a[head].x=x;
	a[head].y=y;
	while(head<tail){
		for(int i=0;i<4;i++){ 
			kx=a[head].x+xx[i];
			ky=a[head].y+yy[i];//从head位置开始向四个方向搜索 
			if(kx<1||kx>n||ky<1||ky>m||c[kx][ky]=='0') continue;//合法判断 
			c[kx][ky]='0';//把已经搜索过的不为0的点标记为0 
			a[tail].x=kx;
			a[tail].y=ky;//搜索到tail的位置 
			tail++;//需要开下一个tail 
		}
		head++; //继续从下一个head开始搜索 
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
			scanf("%s",c[i]+1);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(c[i][j]!='0'){
				c[i][j]='0';
				bfs(i,j);//从i,j开始广搜 
				ans++;//放入队列 计数 
			}
		}
	}
	cout<<ans;
	return 0;
}

例2 OJ1330 最少步数

【分析】

1.选择方法 可以直接从所给位置走到(1,1) 进行两次广搜输出步数 也可以直接从(1,1)开始走 经过所给位置并输出步数

2.注意偏置数组的设置 本题中马既可以走“日” 也可以走“田” 因此有十二个方向

【代码】

#include <bits/stdc++.h>
using namespace std; 
int s[105][105],b[105][105];//s为棋盘,b用来记录步数 
struct  S{
	int x,y;
}a[10005];
int xx[12]={-2,-2,-1,1,2,2,2,2,1,-1,-2,-2};
int yy[12]={1,2,2,2,2,1,-1,-2,-2,-2,-2,-1};
int ax,ay,bx,by; 
void bfs(int x,int y){
	int head,tail;
	head=0,tail=1;
	a[head].x=x;
	a[head].y=y;
	b[x][y]=0;//还没走时(head位置)步数初值为0 
	s[x][y]=1;//标记初始位置为1表明走过 
	while(head<tail){
		int kx,ky;
		for(int i=0;i<12;i++){//日+田 马共有十二个方向 
			kx=a[head].x+xx[i];
			ky=a[head].y+yy[i];
			if(kx<0||kx>100||ky<0||ky>100||s[kx][ky]==1) continue;//判断合法 
			a[tail].x=kx;
			a[tail].y=ky;
			s[kx][ky]=1;//标记走过的点为1 
			b[kx][ky]=b[a[head].x][a[head].y]+1;//b数组计数(原来的值加一) 
			if(kx==1 && ky==1){//当到达点(1,1)时 
				cout<<b[kx][ky]<<endl;//输出步数 
				head=tail;
				break;//两步跳出循环 
			}
			tail++;
		}
		head++;//拓展下一个点 
	}
}
int  main(){
	cin>>ax>>ay>>bx>>by;
	if(ax==1&&ay==1) cout<<0<<endl;
	else bfs(ax,ay); 
	memset(s,0,sizeof(s));//一定要清零 避免留下每次标记造成混乱 
	if(bx==1&&by==1) cout<<0<<endl;//如果初始位置在(1,1)就不需要走 
	else bfs(bx,by);
	return 0;
}

 例3 OJ1251 仙岛求药

【分析】

1.注意不同字符的含义

2.有多组测试数据 需要清零 记得写“当在一行中读入的是两个零时,表示输入结束”

【代码】

#include <bits/stdc++.h>
using namespace std;
char c[25][25];//迷阵 
struct s{
	int x,y;
}a[500];
int b[25][25],l[25][25];//b数组计数,l数组标记走过的点 
int xx[4]={-1,0,1,0};
int yy[4]={0,1,0,-1};
int m,n;
void bfs(int x,int y){
	int head=0,tail=1;
	a[head].x=x;
	a[head].y=y;
	l[x][y]=1;
	int flag=0;//假设不能找到仙药 
	while(head<tail){
		int kx,ky;
		for(int i=0;i<4;i++){
			kx=a[head].x+xx[i];
			ky=a[head].y+yy[i]; 
			if(kx<1||kx>m||ky<1||ky>n||c[kx][ky]=='#'||l[kx][ky]==1) continue;//这里多了一个有怪物('#')的情况 
			a[tail].x=kx;
			a[tail].y=ky;
			l[kx][ky]=1;//标记走过的点 
			b[kx][ky]=b[a[head].x][a[head].y]+1;//计数耶 
			if(c[kx][ky]=='*'){//如果找到了仙药 
				head=tail;
				cout<<b[kx][ky]<<endl;
				flag=1;//标记flag为1 
			}
			tail++;
		}
		head++;//拓展下一个 
	}
	if(flag==0) cout<<-1<<endl;//如果flag仍为0 即不能找到仙药 输出-1 
}
int main(){
	while(cin>>m>>n){
		if(m==0 && n==0) break; //读入数据 遇到两个0时停止 
		memset(l,0,sizeof(l)); 
		memset(b,0,sizeof(b));//记得清零 两个都要T_T 
		int x,y;
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n;j++){
				cin>>c[i][j];//输入矩阵 
				if(c[i][j]=='@'){//李逍遥的位置 
					x=i;
					y=j;//设为起点 
				}
			}
		}
		bfs(x,y);//从起点开始广搜 
	}
	return 0;
}

Practice OJ1255 Maze

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值