B. Frog Traveler(cf)bfs

 原题链接:Problem - 1601B - Codeforces

题目大意:一个青蛙它从井底跳出去。从x点可以网上蹦[0, ax]的距离到y点,到了y点之后又会掉下来by步。问你它最少走多少步出去。问最少步数,想到用bfs。改了一下午代码,真的好细节呜呜。

思路:它其实每次能向上跳到的范围一直往上,用mmin记录,往下跳的点和网上跳的点维护的东西不一样啊啊我又写不出来了但是我有时候能想清楚。这个博主画的图还有写的文很详细:Codeforces-1601 B: Frog Traveler_盖乌咪·A·埃迪尔的博客-CSDN博客

之前看别的博主写的dp先滑再跳,我不是很懂。还是按照顺序来吧。挺难的毕竟1900的题呜呜呜~继续加油!

每个点最多进入队列一次,然后我们又给他加了限制,所以复杂度是O(n)的。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
const double pi = acos(-1.0);
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define rrep(i, n) for (int i = n; i >= (1); --i)
typedef long long ll;
#define sqar(x) ((x)*(x))

const int N = 3e5 + 10;
int a[N], b[N];
int dp[N];
int d[N];
int root[N];
int ans[N], vis[N];//可能在一次的循环中跳到相同的地方,这个时候就没必要push多次了

int main()
{
    int n;
    scanf("%d", &n);
    rep(i, n) scanf("%d", &a[i]);
    rep(i, n) scanf("%d", &b[i]);
    int mmin = n;
    queue<int> q;
    vis[n] = 1;
    root[n] = -1, d[n] = -1;
    q.push(n);
    while(q.size())
    {
        auto temp = q.front();
        q.pop();
        if(temp - a[temp] <= 0)
        {
            dp[0] = dp[temp] + 1, root[0] = temp;
            break;
        }
        if(temp - a[temp] >= mmin) continue;
        for(int i = mmin - 1; i >= temp - a[temp]; i--) //从限制的这位开始
        {
            int now = i + b[i];
            if(vis[now]) continue; //有的点考虑过是从某个点上升又下降得到的,下降得到的那个点之前可能没到过
            vis[now] = 1; //每次是记录下降得到的这个点,上升得到的点是没有被记录的,但是上升得到的是有范围mmin的
            root[now] = temp; //这个点是由哪个点先往上跳再往下跳得来的
            d[now] = i; //跳到这个点是由哪个点往下跳得来的(因为题目要记录)
            dp[now] = dp[temp] + 1;
            q.push(now);
        } //mmin是跳上去的时候可以到达的最小值,与下落得到的那个点有区别
        mmin = temp - a[temp]; //这个范围之内我们都已经考虑过了,下次再有跳到这个范围的就不用考虑了
    }
    if(!dp[0]) puts("-1");
    else{
        printf("%d\n", dp[0]);
        ans[0] = 0;
        int p = root[0]; 
        rep(i, dp[0] - 1)
        {
            ans[i] = d[p]; //d和root数组一起用到,画个图就明白了
            p = root[p];
        }
        for(int i = dp[0] - 1; i >= 0; i--) printf("%d ", ans[i]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值