原题链接: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;
}