KDY----BFS_宽度优先搜索习题

题目由可达鸭提供,本篇够5866字,阅读时注意休息和暂停。

一、课时提交情(AC情况)

T1、武士风度的牛   100/100(老师带着做的。)

T2、抓住那头牛 100/100

T3、仙岛求药    100/100

T4、The Castle  0/100(时间不够了,就看了看题目。)

二、目录

T1、

武士风度的牛

T2、

抓住那头牛

T3、

仙岛求药

T4、

The Castle

三、讲解

T1、

时间限制:1秒        内存限制:128M

题目描述

农民 John 有很多牛,他想交易其中一头被 Don 称为 The Knight 的牛。这头牛有一个独一无二的超能力,在农场里像 Knight 一样地跳(就是我们熟悉的象棋中马的走法)。虽然这头神奇的牛不能跳到树上和石头上,但是它可以在牧场上随意跳,我们把牧场用一个 x,y 的坐标图来表示。这头神奇的牛像其它牛一样喜欢吃草,给你一张地图,上面标注了 The Knight 的开始位置,树、灌木、石头以及其它障碍的位置,除此之外还有一捆草。现在你的任务是,确定 The Knight 要想吃到草,至少需要跳多少次。The Knight 的位置用 K 来标记,障碍的位置用 * 来标记,草的位置用 H 来标记。

这里有一个地图的例子:

11 | . . . . . . . . . .
10 | . . . . * . . . . .
9   | . . . . . . . . . .
8   | . . . * . * . . . .
7   | . . . . . . . * . .
6   | . . * . . * . . . H
5   | * . . . . . . . . .
4   | . . . * . . . * . .
3   | . K . . . . . . . .
2   | . . . * . . . . . *
1   | . . * . . . . * . .
0   ----------------------
                              1
0 1 2 3 4 5 6 7 8 9 0

The Knight 可以按照下图中的 A,B,C,D… 这条路径用 5 次跳到草的地方(有可能其它路线的长度也是 5):

11 | . . . . . . . . . .
10 | . . . . * . . . . .
9   | . . . . . . . . . .
8   | . . . * . * . . . .
7   | . . . . . . . * . .
6   | . . * . . * . . . F<
5   | * . B . . . . . . .
4   | . . . * C . . * E .
3   | .>A . . . . D . . .
2   | . . . * . . . . . *
1   | . . * . . . . * . .
0   ----------------------
                              1
0 1 2 3 4 5 6 7 8 9 0

输入描述

第一行: 两个数,表示农场的列数(< =150)和行数(< =150) 第二行..结尾: 如题目描述的图。

输出描述

一个数,表示跳跃的最小次数

样例

输入

10 11
..........
....*.....
..........
...*.*....
.......*..
..*..*...H
*.........
...*...*..
.K........
...*.....*
..*....*..

输出

5

提示

Hint:这类问题可以用一个简单的先进先出表(队列)来解决。

首先可以看到是最小次数问题(最小步数),所以用BFS来解决。

题解思路:

首先输入整个地图,再输入时也要判断起点和终点即K和H。边判断,边记录k和h的坐标(也就是说AC代码中的sx,sy,ex,ey)。然后就要进行BFS首先先标记,然后将x和y入队。一般的是默认他的头是一步如果说输出比样例大一,那么将这行注释掉,然后就是比较正常的是BFS了,然后就是f小于r就是说队列不为空,然后存一下这个队列的头,头进行查找与他所有相关的邻接点,最后将队头出队。

//AC代码中的部分变量名称用法详解

1.结构体数组q,队列一共是有22500个点(因为图中最大是一个150×150的)。

2.char类型数组a,保存地图时使用150x150的为了防止下标越界各加了5

3.f和r是q队列的头和尾;dep数组储存最小步数

4.dx ,dy就是方向数组

5.vis防止重搜

AC代码如下:

#include<iostream>
using namespace std;
struct dl{
	int h,l;
}q[22500];
char a[155][155];
int f,r,dep[155][155];
int dx[]={-2,-2,-1,-1,1,1,2,2},dy[]={-1,1,-2,2,-2,2,-1,1};
bool vis[155][155];
int m,n,sx,sy,ex,ey;
void BFS(int x,int y){
	vis[x][y]=1;
	q[r].h=x;
	q[r++].l=y;
//	dep[x][y]=1;
	while(f<r){
		int px=q[f].h,py=q[f].l;
		for (int i=0;i<8;i++){
			int nx=px+dx[i],ny=py+dy[i];
			if (nx>=1&&nx<=n&&ny>=1&&ny<=m){
				if (vis[nx][ny]==0&&a[nx][ny]!='*'){
					vis[nx][ny]=1;
					q[r].h=nx;
					q[r++].l=ny;
					dep[nx][ny]=dep[px][py]+1;
				}
			}
		}
		f++;
	}
}
int main(){
	cin>>m>>n;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			cin>>a[i][j];
			if (a[i][j]=='K'){
				sx=i;
				sy=j;
			}
			if (a[i][j]=='H'){
				ex=i;
				ey=j;
			}
		}
	}
	BFS(sx,sy);
	cout<<dep[ex][ey];
	return 0; 
}

T2、

时间限制:1秒        内存限制:128M

题目描述

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0≤N≤100000),牛位于点K(0≤K≤100000)。农夫有两种移动方式: 

1、从X移动到X-1X+1,每次移动花费一分钟 

2、从X移动到2*X,每次移动花费一分钟 

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入描述

两个整数,N和K。

输出描述

一个整数,农夫抓到牛所要花费的最小分钟数

样例

输入
5 17
输出
4

题解思路:

此题目求解的是最小分钟数,也就是说最小步数。所以说此题还是BFS的最小步数问题。

其中题目描述中标黄的就是提示你方向数组该怎么写它是在一个数轴上,但是它不能用数学模拟的方式去模拟它。因为一些数学模拟可能会忽略某种情况,比如说减一再乘二比直接加一要简单。所以说这实际上就可以看成一棵树。如下图(本人没有特别多的美术细胞,请见谅):

就是他判断就是是加1-1还是二乘x这三种情况将其看为一棵树。

 //AC代码中的部分变量名称用法详解

1.结构体数组q,队列一共是有22500个点(因为图中最大是一个150×150的)。

2.char类型数组a,保存地图时使用150x150的为了防止下标越界各加了5

3.f和r是q队列的头和尾;dep数组储存最小步数

4.dx ,dy就是方向数组

5.vis防止重搜

AC代码如下:

#include<iostream>
using namespace std;
const int N=1e5;
int q[N+5],n,k,dep[N+5];
int dx[]={-1,1,2};
int f,r;
bool vis[N+5];
void bfs(int x){
	vis[x]=1;
	q[r++]=x;
	//dep[x]=1;
	while(f<r){
		int px=q[f];
		for (int i=0;i<3;i++){
			int nx;
			if (i<2){
				nx=px+dx[i];
			}
			else{
				nx=px*dx[i];
			}
			if (nx>=0&&nx<=N){
				if (vis[nx]==0){
					vis[nx]=1;
					q[r++]=nx;
					dep[nx]=dep[px]+1;;
				}
			}
		}
		f++;
	}
}
int main(){
	cin>>n>>k;
	bfs(n);
	cout<<dep[k];
	return 0; 
}

T3、

时间限制:1秒        内存限制:128M

题目描述

少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。 

下图 显示了一个迷阵的样例及李逍遥找到仙药的路线。

输入描述

输入有多组测试数据. 每组测试数据以两个非零整数 M 和 N 开始,两者均不大于20。M 表示迷阵行数, N 表示迷阵列数。接下来有 M 行, 每行包含N个字符,不同字符分别代表不同含义: 

1)‘@’:少年李逍遥所在的位置; 

2)‘.’:可以安全通行的方格; 

3)‘#’:有怪物的方格; 

4)‘*’:仙药所在位置。 当在一行中读入的是两个零时,表示输入结束。

输出描述

对于每组测试数据,分别输出一行,该行包含李逍遥找到仙药需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 -1。

样例

输入

8 8
.@##...#
#....#.#
#.#.##..
..#.###.
#.#...#.
..###.#.
...#.*..
.#...###
6 5
.*.#.
.#...
..##.
.....
.#...
....@
9 6
.#..#.
.#.*.#
.####.
..#...
..#...
..#...
..#...
#.@.##
.#..#.
0 0

输出

10
8
-1

题解思路:

此题实际上思路实际上是大概跟第一个题是一样一样的,在此本人就不过多的赘述了。

讲一下注意事项:

1.就是他有多组样例的输入,一定要把vis数组,dep数组,q数组均清零。

2.一定注意,一定注意,要把f和r也要清零。

AC代码如下:

#include<iostream>
#include<cstring>
using namespace std;
struct dl{
	int h,l;
}q[4005];
char a[25][25];
int f,r,dx[]={-1,0,0,1},dy[]={0,-1,1,0};
int n,m,dep[25][25];
bool vis[25][25];
int sx,sy,ex,ey;
void bfs(int x,int y){
	q[r].h=x;
	q[r++].l=y;
	vis[x][y]=1;
	//dep[x][y]=1;
	while(f<r){
		int px=q[f].h,py=q[f].l;
		for (int i=0;i<4;i++){
			int nx=px+dx[i],ny=py+dy[i];
			if (nx>=1&&nx<=m&&ny>=1&&ny<=n){
				if (vis[nx][ny]==0&&a[nx][ny]!='#'){
					q[r].h=nx;
					q[r++].l=ny;
					vis[nx][ny]=1;
					dep[nx][ny]=dep[px][py]+1;	
				}
			}
		}
		f++; 
	}
}
int main(){
	while (cin>>n>>m){
		if (n==0&&m==0){
			break;
		}
		memset(vis,0,sizeof(vis));
		memset(dep,0,sizeof(dep));
		memset(q,0,sizeof(q));
		f=0;
		r=0;
		for (int i=1;i<=n;i++){
			for (int j=1;j<=m;j++){
				cin>>a[i][j];
				if (a[i][j]=='@'){
					sx=i;
					sy=j;
				}
				if (a[i][j]=='*'){
					ex=i;
					ey=j;
				}
			}
		}
		bfs(sx,sy);
		if (dep[ex][ey]==0){
			cout<<"-1"<<endl;
		}
		else{
			cout<<dep[ex][ey]<<endl;
		}
	}
	return 0;
}

T4、

时间限制:1秒        内存限制:128M

题目描述

一座城堡被分成m*n个方块(m≤50,n≤50),每个方块可有0~4堵墙(0表示无墙)。下面示出了建筑平面图:

图中的加粗黑线代表墙。几个连通的方块组成房间,房间与房间之间一定是用黑线(墙)隔开的。 

现在要求你编一个程序,解决以下2个问题: 

1、该城堡中有多少个房间? 

2、最大的房间有多大?

输入描述

平面图用一个数字表示一个方块(第1个房间用二进制1011表示,0表示无东墙,用十进制11表示)。 

第一行一个整数m(m≤50),表示房子南北方向的长度。 

第二行一个整数n(n≤50),表示房子东西方向的长度。

后面的m行,每行有n个整数,每个整数都表示平面图对应位置的方块的特征。每个方块中墙的特征由数字P来描述(0≤P≤15)。数字P是下面的可能取的数字之和: 

1(西墙 west) 

2(北墙 north) 

4(东墙 east) 

8(南墙 south) 

室内的墙被定义两次: 例如方块(1,1)中的南墙也被位于其南面的方块(2,1)定义了一次。 

建筑中至少有两个房间。

输出描述

第1行:一个整数,表示房间总数; 

第2行:一个整数,表示最大房间的面积(方块数)。

样例

输入

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

题解思路:

此期实际上可以就去看我那个最大人工岛DFS的补题报告。此题实际上跟BFS一点儿边都不沾。实际上就是利用多次的DFS求它每一块的连通区域。记录的同时比较每一块儿联通区域的大小,最后输出有几块儿连通区域,然后输出最大的那一块儿。

AC代码如下:

#include<iostream>
using namespace std;
int m,n,a[55][55][5],cnt,maxx,temp,cnt1;
bool vis[55][55];
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
void dfs(int x,int y){
	vis[x][y]=1;
	temp++;
	for (int i=0;i<4;i++){
		int nx=x+dx[i],ny=y+dy[i];
		if (nx>=1&&nx<=m&&ny>=1&&ny<=n){
			if (vis[nx][ny]==0&&a[x][y][i]==0){
				dfs(nx,ny);
			}
		}
	}
}
int main(){
	int t;
	cin>>m>>n;
	for (int i=1;i<=m;i++){
		for (int j=1;j<=n;j++){
			cin>>t;
			cnt1=0;
			while (t!=0){
				a[i][j][cnt1]=t%2;
				t=t/2;
				cnt1++;
			}
		}
	}
	for (int i=1;i<=m;i++){
		for (int j=1;j<=n;j++){
			if (vis[i][j]==0){
				temp=0;
				dfs(i,j);
				cnt++;
				if (maxx<temp){
					maxx=temp;
				}
			}
		}
	}
	cout<<cnt<<endl<<maxx;
	return 0;
}

最后还有一个小投票,欢迎投一下:

  • 17
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值