移动 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;
}