题目阅读
Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.
* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?
生词
fugitive [ˈfju:dʒətɪv] adj. 逃亡的
teleporting n.远距离传送
retrieve [rɪˈtriːv] v.找回
名为FJ的人寻找丢失的牛,这头牛并不移动,可以视为从起点到终点的问题。
并且这里的路只是一条单向路,不同于二维、三维的迷宫,而且只用一维的标记数组就可以实现对迷宫的覆盖,但这道题难点并不在迷宫的表示方法上。
移动方向不仅仅是移动一格,这就可以通过对枚举的次数来选择移动方式
for(i=0;i<3;i++)
{
if(i==0)tx=temp.x+1;
else if(i==1)tx=temp.x-1;
else tx=temp.x*2;
ts=temp.s+1;
}
而且我们需要考虑越界的问题,题目中合法范围是[0,100000],则非法就是
if(tx<0||tx>100000)continue;
对应标记数组定义为
int book[100010];
Input
Line 1: Two space-separated integers: N and K
Output
Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.
求最短路,无疑要用到BFS。然而只写BFS却报了错误Wrong Answer。为什么呢?网上的题解无一例外的标注该题为BFS,但我想强调的是出题者的设坑点在于n,k大小关系导致枚举方向的选择不同,也就是需要分类讨论:
当n>k时,人可以选择的方向只有后退;
当n=k时,人不用走;
当n<k时,可以通过题目给出的三种移动方法:前移、后移、传送来寻找最短路。这里的可以前移后移表现为以坐标为节点的有向图的互相连通的边,例如下图中的2、3节点。
而只写BFS导致n>k这种简单问题复杂为尝试南辕北辙这种无意义且浪费时间的情况,而这是导致WA的原因。
怎么改进呢?很明显由于人只能在相邻方块移动,不难想到两两交换的冒泡排序的求交换次数问题,我们并非需要真的交换元素(移动人的位置),而是通过起点终点坐标的差值即可得到移动步数,即n-k。这个式子同样适合n=k,不妨将这两种情况归位一类。
if(n>=k) {
printf("%d\n",n-k);
return 0;
}
类似利用规律而不采用操作模拟的解法,可以参考Stacks of Flapjacks [UVA - 120]。
当然,我们需要用BFS去求解n>k的情况,同样我们只给出注意的点,而不逐一详细解释代码。
1.方向控制
在上文提过解法,不再赘述。
2.不可走
①越界
同样上文给出了解释
②访问过的结点。
它记录的步数一定是最短路径能达到的步数,因为BFS的每层结点都是能到达该节点的最短步数,因而不需要考虑记录并更新到达每个位置步数的最小值(受《啊哈算法》第四章第2节解救小哈 解法的影响)
if(!book[tx])
最后,不妨贴出源码:
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int n,k;
int book[100010];
struct node{
int x,s;
};
int main(){
freopen("test.txt","r",stdin);
cin>>n>>k;
if(n>=k) {
printf("%d\n",n-k);
return 0;
}
queue<node> que;
int i,tx,ts,flag=0;;
memset(book,0,sizeof(book));
struct node t,temp;
t.x=n;
t.s=0;
que.push(t);
book[n]=1;
while(!que.empty()){
temp=que.front();
for(i=0;i<3;i++)
{
if(i==0)tx=temp.x+1;
else if(i==1)tx=temp.x-1;
else tx=temp.x*2;
ts=temp.s+1;
if(tx<0||tx>100000)continue;
if(!book[tx])
{
t.x=tx;
t.s=ts;
book[tx]=1;
que.push(t);
if(tx==k){
cout<<que.back().s;
return 0;
}
}
}
que.pop();
}
return 0;
}