最小转弯问题【BFS】

Description

给出一张地图,这张地图被分为 n × m ( n , m < = 100 ) n×m(n,m<=100) n×mn,m<=100)个方块,任何一个方块不是平地就是高山。平地可以通过,高山则不能。现在你处在地图的 ( x 1 , y 1 ) (x1,y1) x1,y1这块平地,问:你至少需要拐几个弯才能到达目的地 ( x 2 , y 2 ) (x2,y2) x2,y2?你只能沿着水平和垂直方向的平地上行进,拐弯次数就等于行进方向的改变(从水平到垂直或从垂直到水平)的次数。例如:如图 1 1 1,最少的拐弯次数为 5 5 5


Input
1 1 1行: n ∗ m n*m nm 2 2 2 n + 1 n+1 n+1行:整个地图地形描述(0:空地;1:高山), 如图,第2行地形描述为:1 0 0 0 0 1 0 第3行地形描述为:0 0 1 0 1 0 0 …… 第 n + 2 n+2 n+2行:x1 y1 x2 y2 (分别为起点、终点坐标)

Output
s (即最少的拐弯次数


Sample Input
5 7
1 0 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 0 1 0 1
0 1 1 0 0 0 0
0 0 0 0 1 1 0
1 3 1 7

Sample Output
5


解题思路

很明显,这又又…又是一道BFS,唯一变化的是让我们统计拐弯。
一共只有4个方向,上下为一种,左右为一种,可以模2判断。
我是把上下设为2,4方向,模2余0,左右设为1,3方向,模2余1,记录方向模2的值。
好了,真棒。。。!(╯▽╰)!
但,你以为你真的做完了吗? 不,因为研究发现(其实是老师讲的),可能有多种方法能到,而因为方向的顺序,你先找到的结果的结果不是最小的结果,所以如果这道题的数据比较水,这种方法你是可以过得,但,还是不要抱着侥幸心理。。。
正解:
最小转弯,不是最少步数。把拓展方式从4个方向一个格改成从4个方向撞到墙为止的一次性拓展完。(用老师的说法就是代价相同)
不过注意:封路和墙不要混为一谈。因为他是撞到墙才停止拓展,而碰到已经被走过的路只不过是不入队而不是不继续拓展。(被卡了好一会qAq)


代码

第一个思路:(不是正解但竟然A了,谁能告诉我为什么,在评论请回复呀)ヾ(◍°∇°◍)ノ゙

#include<iostream>
#include<cstdio>
using namespace std;
const int dx[5]={0,0,1,0,-1};
const int dy[5]={0,1,0,-1,0};
int n,m,a,b,c,d,bsy[200][200];
int st[200][3],fa[200];//st[][1]记录横坐标,st[][2]表示纵坐标,st[][3]记录拐弯数,fa记录方向模2的值
int h=0,t=1;
bool check(int x,int y)
{
	if(x>0&&x<=n&&y>0&&y<=m&&!bsy[x][y])
	return 1;
	else
	return 0;
}
void bfs(){
	fa[1]=-1;//后面有解释
	st[1][1]=a;
	st[1][2]=b;
	st[1][3]=0;
	bsy[a][b]=1;
	do{
		h++;
		for(int k=1;k<=4;k++)
		{
			if(check(st[h][1]+dx[k],st[h][2]+dy[k])){
			   t++;
			   fa[t]=k%2;
			   st[t][1]=st[h][1]+dx[k];
			   st[t][2]=st[h][2]+dy[k];
			   if(fa[t]!=fa[h])
			     st[t][3]=st[h][3]+1;
			     else st[t][3]=st[h][3];
			   bsy[st[t][1]][st[t][2]]=1;//标记走过
			   if(st[t][1]==c&&st[t][2]==d) 
			   {
			      cout<<st[t][3]-1;//-1是因为前面起点的fa设为了-1,第一次走也算成了拐弯
			      return;
			   }
			} 
		}
	}while(h<=t);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
			scanf("%d",&bsy[i][j]);
	}
	scanf("%d%d%d%d",&a,&b,&c,&d);
	bfs(); 
}

正解代码:

#include<cstdio>
using namespace std;
int head,tail,n,m,state[10001][3],c,s,x,y,qx,qy;
bool ok[101][101],a[101][101];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};//拓展方向
void bfs()
{
	head=0;
	tail=1;
	do
	{
		head++;//出队
		for (int i=0;i<4;i++)//4个方向
		{
			x=state[head][0];y=state[head][1];
			int j=1;
			while (!a[x+dx[i]*j][y+dy[i]*j] && x+dx[i]*j<=n && y+dy[i]*j<=m && x+dx[i]*j>0 && y+dy[i]*j>0)
			//如果碰到墙或边缘就结束拓展
			{
			  if (!ok[x+dx[i]*j][y+dy[i]*j])
			  //如果已经走过的路线就不入队
			  {
			  	tail++;//入队
			  	state[tail][0]=x+dx[i]*j;
			  	state[tail][1]=y+dy[i]*j;//储存位置
			  	state[tail][2]=state[head][2]+1;//储存转弯数
			  	ok[x+dx[i]*j][y+dy[i]*j]=true;//已经走过该地
			  	if (x+dx[i]*j==qx && y+dy[i]*j==qy)//结束判断
			  	{
			  		s=state[tail][2];
			  		return;
			  	}
			  }
			  j++;//下一个拓展
			}
		}
	}
	while(head<tail);//空队退出
}
int main()
{
	scanf("%d%d\n",&n,&m);		
	for (int i=1;i<=n;i++)
	{
	  for (int j=1;j<=m;j++)
	  {
	  	scanf("%d",&c);
	  	if (c!=0) a[i][j]=true;
	  }
	}
	scanf("%d%d%d%d",&state[1][0],&state[1][1],&qx,&qy);
	//输入不解释
	bfs();//函数不解释
	printf("%d",s-1);//输出不解释
}
<think>嗯,用户想了解东方博宜系统中的最小拐弯路径算法及其实现。首先,我需要回忆一下这个问题的背景。最小拐弯路径通常是在网格或矩阵中找到从起点到终点转弯次数最少的路径,类似于迷宫寻路问题,但优化目标是减少转弯次数而不是路径长度。 根据用户提供的引用,追梦算法中提到当方向走到底时,从走过的路径中取出点作为新起点继续延伸,这样能保证拐弯数最少[^1]。这说明该算法可能采用了广度优先搜索(BFS)的策略,优先探索同一方向上的所有可能路径,以减少转弯次数。另外,动态规划在路径问题中也有应用,如三角形最小路径和问题中使用动态规划从底部向上递推[^2],这可能为最小拐弯路径提供思路。 接下来,我需要考虑如何结合这两个引用内容。BFS适合处理状态空间中的最短路径问题,而动态规划适用于有重叠子问题的情况。对于最小拐弯路径,可能需要记录每个位置和方向的转弯次数,并优先处理转弯次数少的路径。 可能的实现步骤包括:定义方向(上下左右),使用队列进行BFS,记录每个点的到达方向和已转弯次数,遇到终点时返回结果。同时,需要维护一个访问数组,记录到达该点的最小转弯次数,避免重复处理。 然后,需要验证这种思路是否正确。比如,在每一步中,如果沿当前方向继续走,转弯次数不变;如果改变方向,则次数加一。这样,通过优先处理转弯次数少的节点,可以确保最先到达终点的路径转弯最少。 用户可能还需要具体的代码示例。参考动态规划的例子[^2],可以尝试用类似的结构,但结合BFS。可能需要一个三维数组来存储每个位置在不同方向下的最小转弯次数。 最后,生成相关问题需要考虑用户可能的后续疑问,比如与其他算法的比较、时间复杂度的分析,或者实际应用场景。</think>### 东方博宜 最小拐弯路径 算法解析 最小拐弯路径问题的核心是在网格地图中寻找从起点到终点转弯次数最少的路径。该问题通常采用**广度优先搜索(BFS)的变体**结合方向优先级策略来实现[^1]。 #### 算法核心思路 1. **方向延续性** 每次移动时,优先沿当前方向延伸到底,避免频繁切换方向导致转弯次数增加。例如,若当前向右移动,则尽可能向右走完所有可行格子,再考虑其他方向。 2. **状态记录** 需要记录每个坐标点的**到达方向**和**已累积的转弯次数**,避免重复访问相同状态。例如: $$状态 = (x, y, dir, turns)$$ 其中`dir`表示当前方向,`turns`表示已转弯次数。 3. **优先级队列优化** 使用优先队列(按转弯次数排序)或分层BFS,优先处理转弯次数更少的路径分支,确保首次到达终点时即为最优解。 #### 代码实现框架(Python示例) ```python from collections import deque def min_turn_path(grid, start, end): directions = [(0,1), (1,0), (0,-1), (-1,0)] # 右、下、左、上 m, n = len(grid), len(grid[0]) visited = [[[float('inf')] * 4 for _ in range(n)] for _ in range(m)] q = deque() # 初始化四个方向 for i in range(4): dx, dy = directions[i] nx, ny = start[0] + dx, start[1] + dy if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 0: q.append((start[0], start[1], i, 0)) # (x,y,方向,转弯次数) visited[start[0]][start[1]][i] = 0 while q: x, y, dir, turns = q.popleft() if (x, y) == end: return turns # 沿当前方向延伸 dx, dy = directions[dir] nx, ny = x + dx, y + dy if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 0: if visited[nx][ny][dir] > turns: visited[nx][ny][dir] = turns q.appendleft((nx, ny, dir, turns)) # 优先处理直行路径 # 尝试转弯(方向改变时转弯次数+1) for new_dir in range(4): if new_dir == dir: continue dx, dy = directions[new_dir] nx, ny = x + dx, y + dy if 0 <= nx < m and 0 <= ny < n and grid[nx][ny] == 0: if visited[nx][ny][new_dir] > turns + 1: visited[nx][ny][new_dir] = turns + 1 q.append((nx, ny, new_dir, turns + 1)) return -1 ``` #### 关键优化点 1. **双向BFS**:同时从起点和终点开始搜索,提升效率 2. **方向剪枝**:若当前方向无法到达终点,提前终止分支 3. **动态规划思想**:类似三角形最小路径和问题,通过状态转移记录最优子结构
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值