Hrbust-1316-移动 II(广度优先搜索 路径记录)

移动 II
Time Limit: 1000 MS Memory Limit: 65536 K
Total Submit: 461(134 users) Total Accepted: 204(124 users) Rating: Special Judge: No
Description
在坐标轴[0,500]上存在两点A,B。

点A可以多次移动,每次移动需要遵循如下规则:

1.向后移动一步。

2.向前移动一步。

3.跳到当前坐标*2的位置上。

要求:利用宽搜算法编程求解从A移动到B的步数最少的方案,为使答案统一,要求搜索按照规则1、2、3的顺序进行。

Input
输入包含多组测试用例。

每组测试用例要求输入两个整数A,B。

Output
按要求输出步数最少的方案。

向后走输出”step back”。

向前走输出”step forward”。

跳跃输出”jump”。

对于每组结果需要追加一个空行。

Sample Input
5 17
5 18
3 499
Sample Output
step back
jump
jump
step forward

jump
step back
jump

step forward
jump
jump
jump
step back
jump
jump
step forward
jump
jump
step back

相对于简单的广搜,多了个路径的记录,将队列中走过的每个动作记录到数组中。
分三个部分:

第一部分:先进行普通的简单广搜,其中在塞入每一步到队列中时,同时将每次到达的路径记录于一个path数组中。path数组是采取类似链表的方式存储路径的。

第二部分:处理path数组,从目的地处倒着回溯到初始位置。虽然path中记录着很多路径,而且有的可能是广搜过程中未达到目的地的无用地点,但是这不影响从目的地倒着回溯到出发点。【path数组中数组标号表示位置坐标,数组标号中存储(对应)的信息,表示是从哪个坐标到达这个数组标号位置的】将倒着回溯时,返回上一个位置的”方式”记录下来,比如从5的位置回溯到4的位置,说明从4是通过向前走一步到达5位置的,因此在road数组中,记录下这个步骤是向前走一步。

第三部分:根据处理后的path数组,所得到的road数组,倒序输出每一步的动作

#include<stdio.h>///广搜路径记录
#include<queue>
#include<string.h>
using namespace std;
bool vis[600];///标记数组
int path[600];///路径记录数组,每个新坐标的数组下标记录着上一次停留的坐标
int main()
{
    int start,stop,i;
    queue<int>q;
    while(scanf("%d%d",&start,&stop)!=EOF)
    {
        memset(vis,false,sizeof(vis));
        memset(path,-1,sizeof(path));
        while(!q.empty())
        {
            q.pop();
        }
        q.push(start);
        vis[start]=true;
        while(!q.empty())///第一部分,广搜找到最短路径,并记录路径
        {
            int walk=q.front();
            q.pop();
            if(walk==stop)
            {
                break;
            }
            for(i=1;i<=3;i++)///分顺序的三步,必须,1向后,2向前,3跳跃
            {
                int will;
                if(i==1)
                {
                    will=walk-1;
                }
                if(i==2)
                {
                    will=walk+1;
                }
                if(i==3)///先判断怎么走
                {
                    will=walk*2;
                }
                if(will>=0&&will<=500&&!vis[will])///再判断这样走符不符合条件
                {
                    vis[will]=true;
                    path[will]=walk;///符合条件就记录下一个坐标到路径数组中,这里相当于链表的存储方式,数组标号表示坐标,数组中存储的数字表示到达标号之前的位置
                    q.push(will);
                }
            }
        }
        int backto=stop;///第二部分,从目的地,利用路径记录数组,回溯到起点,并根据路径数组中存储的坐标点之间的关系【这里先初始化回溯指针backto为结束位置】
        int flag=0;                                                          ///判断每一步的动作是向前,向后,还是跳跃
        int road[600];///第三个数组,记录每一步的路径动作,分别用123表示三种动作
        while(path[backto]!=-1)///循环条件是找的每一步都存储有上一步的路径,直到找到的起点是没有存储路径的-1
        {
            if(path[backto]==backto+1)///当前坐标与存储坐标的关系为+1时,说明当前坐标是存储坐标后退得到的
            {
                road[flag++]=1;///标记此步骤为1(后退)
                backto=path[backto];///记住要回溯
            }
            else if(path[backto]==backto-1)///说明当前坐标是存储坐标向前一步得到的
            {
                road[flag++]=2;
                backto=path[backto];
            }
            else///不能用三个if,判断条件会重复,剩下的情况只有跳跃了,若用三个if,则通过了上一步的后退,仍会可能符合条跳跃的条件关系
            {
                road[flag++]=3;
                backto=path[backto];
            }
        }
        for(i=flag-1;i>=0;i--)///第三部分,根据动作数组存储的路径,倒着输出每个动作,因为动作记录时是从终点到起点的
        {
            if(road[i]==1)///根据动作数组存储的动作代号来判断输出动作
            {
                printf("step back
");
            }
            if(road[i]==2)
            {
                printf("step forward
");
            }
            if(road[i]==3)
            {
                printf("jump
");
            }
        }
        printf("
");

    }
    return 0;
}
原文地址:https://www.cnblogs.com/kuronekonano/p/11794345.html