当青训营遇上码上掘金
题目
小青要找小码去玩,他们的家在一条直线上,当前小青在地点 N ,小码在地点 K (0≤N , K≤100 000),并且小码在自己家原地不动等待小青。小青有两种交通方式可选:步行和公交。
步行:小青可以在一分钟内从任意节点 X 移动到节点 X-1 或 X+1
公交:小青可以在一分钟内从任意节点 X 移动到节点 2×X (公交不可以向后走)
请帮助小青通知小码,小青最快到达时间是多久?
输入: 两个整数 N 和 K
输出: 小青到小码家所需的最短时间(以分钟为单位)
思路
BFS
先来写一个复杂度高的,但是好理解的。
最简单莫过于写个BFS了。直接进行广搜,每一步会衍生出三种下一步,BFS遍历即可得到结果。
当我们处于一个位置时,我们有三种动作,分别是前进1、后退1、乘2操作。采用BFS模式,我们将三种动作产生的结果放在队列的尾部,这样当我们处理完这一层的节点时,才会处理产生的节点,从而进行BFS。
但BFS的解法问题也很明显,就是时间复杂度高了。为O(n^3)。
DP (未验证)
为了青豆:>
我第一眼看这题想的是动态规划,但一下子没有想好状态转移方程所以暂时搁置了。
如果我们的k是奇数,那么我们必定要进行+1或者-1的操作才能到达,如果我们k是偶数,那就是坐公交车到达(也存在离得近的,可以直接步行到达。)。
拓展到整体,就是奇数节点的情况。
注意要处理n之前的数据。
代码
BFS:
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int main() {
typedef pair<int, int> Node;
int n, k;
cin >> n >> k;
queue<Node> q;
q.push({n, 0});
while(1) {
auto now = q.front();
if (now.first == k) {
cout << now.second << endl;
break;
}
q.push({now.first - 1, now.second + 1});
q.push({now.first + 1, now.second + 1});
q.push({now.first * 2, now.second + 1});
q.pop();
}
return 0;
}
DP:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
int main() {
int dp[100000+20];
memset(dp, 0, sizeof(int)*100000)
int n, k;
cin >> n >> k;
for (int i = n; i >= 0; i--) {
dp[i-1] = dp[i] + 1;
}
for (int i = n; i <= k; i++) {
if(i % 2 == 0) {
dp[i] = min(dp[i/2], min(dp[i-1], dp[i + 1]));
} else {
dp[i] = min(dp[i-1], dp[i+1]);
}
if (i == k) break;
}
cout << dp[k] << endl;
return 0;
}