问题描述
农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点 (0<=N<=100000),牛位于点 K(0<=K<=100000)。农夫有两种移动方式:
- 从X移动到X-1或X+1,每次移动花费一分钟
- 从X移动到2*X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?
问题分析
假设农夫起始位于点3,牛位于 5,N=3,K=5,最右边是 6。如何搜索到一条走到5的路径?
策略:广度优先搜索
给节点分层。起点是第 0 层。从起点最少需 n 步就能到达的点属于第 n 层。
第 1 层:2,4,6
第 2 层:1,5
第 3 层:0
依层次顺序,从第一层开始扩展节点,每层的节点用队列保存。扩展时,不能扩展出已经走过的节点(需要判重) 。
这里可以参考树的层序遍历。
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
int N, K;
const int MAXN = 100000;
int visited[MAXN + 10]; //判重标记,visited[i] = true表示i已经扩展过
struct Step {
int x; //位置
int steps; //到达x所需的步数
Step(int xx, int s) :x(xx), steps(s) { }
};
queue<Step> q; //队列,即Open表
int main() {
cin >> N >> K;
memset(visited, 0, sizeof(visited));
q.push(Step(N, 0));
visited[N] = 1;
while (!q.empty()) {
Step s = q.front();
if (s.x == K) { //找到目标
cout << s.steps << endl;
return 0;
}
else {
if (s.x - 1 >= 0 && !visited[s.x - 1]) {
q.push(Step(s.x - 1, s.steps + 1));
visited[s.x - 1] = 1;
}
if (s.x + 1 <= MAXN && !visited[s.x + 1]) {
q.push(Step(s.x + 1, s.steps + 1));
visited[s.x + 1] = 1;
}
if (s.x * 2 <= MAXN &&!visited[s.x * 2]) {
q.push(Step(s.x * 2, s.steps + 1));
visited[s.x * 2] = 1;
}
q.pop();
}
}
return 0;
}