Frog Traveler 最短路,bfs剪枝,打印路径

在这里插入图片描述
题意 :

  • 给两个长度为n的数组,初始位于索引n,目标是越过索引1,注意不能往后跳,每次可以跳0到 a [ i ] a[i] a[i]米,即,身处索引 i i i,可以跳 [ 0 , a [ i ] ] [0, a[i]] [0,a[i]]中的任意米,但是从i跳到j,会后退b[j]步,问最少多少步可以跳出, n < = 3 e 5 n<=3e5 n<=3e5,并打印每次跳后到达地方的位置坐标(下滑前)

思路 :

  • 从n开始bfs,每次将跳到且下滑后的点入队,维护到达这个点的最小步数
  • 优化剪枝是维护之前能到的最高(数值最小)的位置,枚举当前点能到达的点,如果低于等于最高位置,说明后面跳的更少的方案都可以被剪枝了(因为对于同一个点下滑的距离是确定的,只是跳的距离可以选择),break;并用当前点能到的最高的点维护最高位置
  • 打印路径,由于是输出下滑前的点,而我们入队用的是下滑后的点,所以再开一个ans数组映射
  • 打印路径的具体方案 :从终点开始,将点放入栈中,点变为其前驱,直到没有前驱(即前驱为-1),然后再依次取出栈顶即可
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>

using namespace std;

const int N = 3e5 + 10;

int n, mi;
int a[N], b[N];
int pre[N], dist[N], ans[N];

int bfs()
{
    
    
    mi = n;

    queue<int> q;
    memset(dist, 0x3f, sizeof dist);
    memset(pre, -1, sizeof pre);
    memset(ans, 0, sizeof ans);

    dist[n] = 0;
    q.push(n);

    while (q.size())
    {
    
    
        int t = q.front(); q.pop();

        if (t == 0) return dist[t];

        for (int i = a[t]; i > 0; i -- )
        {
    
    
            int now = t - i;    // 下滑前
            int temp;
            if (now >= mi) break;
            if (now <= 0) temp = 0, now = 0;
            else temp = now, now = now + b[t - i];  // temp是下滑前,now是下滑后

            if (dist[now] > dist[t] + 1)
            {
    
    
                dist[now] = dist[t] + 1;
                pre[now] = t;
                ans[now] = temp;    // 映射
                q.push(now);
            }
        }

        mi = min(mi, t - a[t]);
    }

    return -1;
}

int main()
{
    
    
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

    int _ = 1;
//    cin >> _;

    while (_ -- )
    {
    
    
        cin >> n;
        for (int i = 1; i <= n; i ++ ) cin >> a[i];
        for (int i = 1; i <= n; i ++ ) cin >> b[i];

        cout << bfs() << endl;

        // 打印路径 倒序输出

        stack<int> stk;
        int x = 0;
        while (pre[x] != -1)
        {
    
    
            stk.push(x);
            x = pre[x];
        }

        while (!stk.empty())
        {
    
    
            int now = stk.top(); stk.pop();
            cout << ans[now] << ' ';
        }
        cout << endl;
    }

    return 0;
}

Guess you like

Origin blog.csdn.net/m0_51448653/article/details/121223023