hdu4230 Robot Navigation 迷宫最短路径的条数 BFS 很霸气!!!!!

本文介绍了一种使用广度优先搜索(BFS)算法解决机器人路径规划问题的方法,旨在找到从起点到终点的最短命令序列及其数量。通过维护一个三维数组记录路径信息,实现了对不同方向移动情况的有效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题意是这个的,有一个robot,要从起点走到终点(简化版),它只接受三种命令,

FORWARDX:moveforwardbyXunits.
TURNLEFT:turnleft(inplace)by90degrees.
TURNRIGHT:turnright(inplace)by90degrees.

问:robot从起点走到终点,最短的命令串的长度是多少,有多少条这样的命令串可以走到终点。

至于FORWARDX:moveforwardbyXunits.

也就是说给robot一个向前的命令,它可以走到他前面的任意一个“.”直到遇到“*”或者出了边界。如:

56

*....X

.....*

.....*

.....*

N....*

对于图中红色的点,robotN开始走,只要一个向前的命令就可以走到图中所有的红色点

/*思路 和以前的相比 只要添加一个3维数组记录到每个点的信息即可 即 坐标x y方向dir 三个量
记录下来 到每个点所用的最短时间和路数
*/
#include<stdio.h>/*BFS去求最短的路径的条数 是不能标记用没用过的*/
#include<string.h>
#include<limits.h>
#include<queue>
using namespace std;
#define mod 1000000
int hang,lie,e_x,e_y;
char map[105][105];
struct haha
{
int x;
int y;
int time;
int dir; // 不能够用优先队列 要用队列 因为要从某个点向4边扩散记录数组a
// friend bool operator <(struct haha a,struct haha b)
// {
// return a.time>b.time;
// }

}now,next,begin;
struct xixi
{
int num;/*当前最短的次数*/
int time;
}a[105][105][4];
int step[4][2]={-1,0,0,1,1,0,0,-1};

int can(int x,int y)
{
if(x>=0&&x<hang&&y>=0&&y<lie&&map[x][y]=='.')
return 1;
return 0;
}

void BFS()
{
int i,k,xx,yy,ans,ti;
queue<struct haha>que;
que.push(begin);
a[begin.x][begin.y][begin.dir].num=1;/*这里的初始化 千万不要忘记*/
a[begin.x][begin.y][begin.dir].time=0;
while(!que.empty())
{
now=que.front();
que.pop();
if(now.x==e_x&&now.y==e_y) continue;


for(i=0;i<4;i++)
{
xx=now.x+step[i][0];
yy=now.y+step[i][1];
if(!can(xx,yy)) continue; /*看忘各个方向试试能不能走 如果不能走 继续下面的也没有意义了 尤其是转身 都不能走了 你转身干嘛啊*/
if(now.dir==i)/*只有当方向正好与我们要走的方向一样的时候 我们就走*/
{
k=1;/*操 k=1 放进了while里面 一个劲死循环*/
while(1)
{
xx=now.x+step[i][0]*k;
yy=now.y+step[i][1]*k;
if(can(xx,yy))
{
next.dir=i;
next.time=now.time+1;
next.x=xx;
next.y=yy;
if(a[xx][yy][i].time>now.time+1)
{
a[xx][yy][i].time=now.time+1;
a[xx][yy][i].num=a[now.x][now.y][now.dir].num;
a[xx][yy][i].num=a[xx][yy][i].num%mod;/*可以去掉*/
que.push(next);

}
else if(a[xx][yy][i].time==now.time+1)
{
a[xx][yy][i].num+=a[now.x][now.y][now.dir].num;
a[xx][yy][i].num=a[xx][yy][i].num%mod;/*这里就没有必要push了 否则会死循环*/
}

}
else break;
k++;
}
}
else
if(now.dir==(i+2)%4)/*方向和我们要走的方向相反 这时候只转身 等一样了再走*/
{
next.time=now.time+2;
next.dir=i;
next.x=now.x;
next.y=now.y;
if(a[now.x][now.y][i].time>now.time+2)
{/*a[now.x][now.y][now.dir].time+2一开始上面写成这样了不是和当前点的其它方向比 而是找和上一状态到当前状态所用时间的较短的一个*/
a[now.x][now.y][i].time=now.time+2;
a[now.x][now.y][i].num=a[now.x][now.y][now.dir].num;
a[now.x][now.y][i].num=a[now.x][now.y][i].num%mod;
que.push(next);
}
else if(a[now.x][now.y][i].time==now.time+2)
{
a[now.x][now.y][i].num+=a[now.x][now.y][now.dir].num;/*我擦 这里居然让我加了个2 */
a[now.x][now.y][i].num=a[now.x][now.y][i].num%mod;
}

}
else
{
next.time=now.time+1;
next.dir=i;
next.x=now.x;
next.y=now.y;
if(a[now.x][now.y][i].time>now.time+1)
{
a[now.x][now.y][i].time=now.time+1;
a[now.x][now.y][i].num=a[now.x][now.y][now.dir].num;
a[now.x][now.y][i].num=a[now.x][now.y][i].num%mod;
que.push(next);
}
else if(a[now.x][now.y][i].time==now.time+1)
{
a[now.x][now.y][i].num+=a[now.x][now.y][now.dir].num;
a[now.x][now.y][i].num=a[now.x][now.y][i].num%mod;
}

}



}
}
ans=INT_MAX;ti=0;
for(i=0;i<4;i++)
{
if(ans>a[e_x][e_y][i].time)
{
ans=a[e_x][e_y][i].time;
ti=a[e_x][e_y][i].num;
}
else if(ans==a[e_x][e_y][i].time)
{
ti+=a[e_x][e_y][i].num;
ti=ti%mod;
}

}
if(ans==INT_MAX) printf("0 0\n");
else
printf("%d %d\n",ans,ti);
return ;
}

int main()
{
int i,j;
while(scanf("%d %d",&hang,&lie)!=EOF)
{
if(hang+lie==0) break;
for(i=0;i<hang;i++)
for(j=0;j<lie;j++)
for(int k=0;k<4;k++)
{
a[i][j][k].time=INT_MAX;
a[i][j][k].num=0;
}

for(i=0;i<hang;i++)
{
scanf("%s",map[i]);
for(j=0;j<lie;j++)
{
if(map[i][j]=='X') {e_x=i;e_y=j;map[i][j]='.';}
if(map[i][j]=='N') {begin.dir=0;begin.time=0;begin.x=i;begin.y=j;}
else if(map[i][j]=='E') {begin.dir=1;begin.time=0;begin.x=i;begin.y=j;}
else if(map[i][j]=='S') {begin.dir=2;begin.time=0;begin.x=i;begin.y=j;}
else if(map[i][j]=='W') {begin.dir=3;begin.time=0;begin.x=i;begin.y=j;}
}

}
BFS();
}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值