寻友之旅 | 码上掘金

48 阅读2分钟

当青训营遇上码上掘金

题目

小青要找小码去玩,他们的家在一条直线上,当前小青在地点 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是偶数,那就是坐公交车到达(也存在离得近的,可以直接步行到达。)。

拓展到整体,就是奇数节点的情况。

dp[k]=min(dp[k1],dp[k+1])+1,if k%2 == 1dp[k]=min(dp[k/2],dp[k1],dp[k+1])+1,if k%2 == 1dp[k] = min(dp[k-1], dp[k+1]) + 1, if \ k \% 2 \ == \ 1 \\ dp[k] = min(dp[k/2], dp[k-1],dp[k+1]) + 1, if \ k \% 2 \ == \ 1

注意要处理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;
}