题意:
给定两个整数n和k
通过 n+1或n-1 或n*2 这3种操作,使得n==k
输出最少的操作次数
思路: 3个方向的BFS【+1,-1,*2】
注意: 因为数据比较大,直接套模板BFS会TLE,
应该适当剪枝:
1,当n>=k时,直接可知最少步数n-k【只能通过后退一步来到达位置k】
如果此处进入BFS则会浪费很多时间!
2,如果BFS到当前位置大于k,那么以后的+1都不会到达小牛的位置。
也只能通过后退一步的方式来达到k,所以当当前位置大于k是不需要
继续判断+1的情况了。
3,同2,如果当前位置比k还大,也是只能通过后退的方式达到k,
所以*2的情况也不用考虑。
/*
POJ 3278
问题1186
Memory 5400
Time 1420
*/
#include<iostream>
#include<cstring>
#include<queue>
#include<stdio.h>
using namespace std;
const int MAXN = 1000050;
int vis[MAXN+1];
int n, k;
struct Node
{
int x, step;
};
int bfs(int start)
{
memset(vis, 0, sizeof(vis));
queue<Node>Q;
Node temp;
temp.x = start;
temp.step = 0;
vis[temp.x] = 1;
Q.push(temp);
while (!Q.empty())
{
Node h;
h = Q.front();
Q.pop();
if (h.x == k)
{
return h.step;
}
if (h.x + 1 <= k&&vis[h.x + 1] == 0)//剪枝,如果当前位置大于k,
{ //那么以后的+1都不会到达小牛的位置。
Node next;
vis[h.x + 1] = 1;
next.x = h.x + 1;
next.step = h.step + 1;
Q.push(next);
}
if (h.x - 1 >= 0 && vis[h.x - 1] == 0)
{
Node next;
vis[h.x - 1] = 1;
next.x = h.x - 1;
next.step = h.step + 1;
Q.push(next);
}
if ((h.x <= k)&&(h.x * 2 <= MAXN) && vis[h.x * 2] == 0)
{ //如果当前位置比k还大那么下一次*2会更大
Node next; //后退只能-1,那么本来就比k大,那么可以后退
vis[h.x * 2] = 1; //(当前位置步-k步),而再*2那就得后退(当前位置*2-k步)
next.x = h.x * 2;
next.step = h.step + 1;
Q.push(next);
}
}
return 0;
}
int main()
{
while (scanf("%d %d",&n,&k)!=EOF)
{
if (n >= k)//剪枝,当n大于k时,n只能通过后退
{ //一步来达到k,不需要进入bfs,不然会TLE
cout << n - k << endl;
}
else
{
printf("%d\n", bfs(n));
}
}
return 0;
}