【题目描述】
小H发明了一个跳格子的游戏,地板上画了排成一排的n个格子,并以1…n按顺序编号。他规定第i个格子可以跳到第1到第i-1个格子中的任一个,且每个格子有一个不一定相同的反方向的跳跃度a[i],代表第i个格还可以跳到第i+1到i+a[i]个格子中的任一个。现在小H指定其中的一个格子,问从这个格子开始,最少需要连续踩几次格子(起始的格子也算在内),可以跳到第n个格子的后方,即若第k个格子有k+a[i]>n,那么从第k个格子就可以跳到第n个格子的后方。
【输入格式】
输入的第1行包含两个正整数n,m,为格子的数目以及询问的次数。
第2行包含n个正整数,第i个正整数为a[i],即第i个格子向反方向最大跳跃的长度。
第3行包含了m个正整数,为询问从哪一个格子开始,最少要几次跳到第n个格子的后方。
数字之间用空格隔开。
【输出格式】
输出包含1行,这一行有m个正整数,对于每一个询问,输出最少需要踩的格子数,数字之间用空格隔开。 行末换行且没有多余的空格。
【样例输入#1】
5 5
2 4 1 1 1
1 2 3 4 5
【样例输出#1】
2 1 2 2 1
【样例解释#1】
若从第1个格子开始则跳到第2个格子,接着就可以跳到第n个格子的后方。
若从第3个格子开始则同样跳到第2个格子。
若从第4个格子开始可以跳到第2个格子或最后一个格子,接着跳出第n个格子,答案同样为2。
【数据规模】
对于20%的数据,有n≤10;
对于40%的数据,有n≤100,m≤10;
对于60%的数据,有n≤1000,a[i]≤1000,m≤500;
对于100%的数据,有n≤100000,a[i]≤n,m≤50000
来自AI:
以下是使用动态规划解决此问题的 C++ 代码:
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
vector<int> solve(vector<int>& a, int n) {
vector<int> dp(n + 1, INT_MAX);
dp[n] = 0;
for (int i = n - 1; i >= 1; --i) {
for (int j = i + 1; j <= min(i + a[i], n); ++j) {
if (dp[j]!= INT_MAX) {
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
return dp;
}
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
vector<int> queries(m);
for (int i = 0; i < m; ++i) {
cin >> queries[i];
}
vector<int> dp = solve(a, n);
for (int i = 0; i < m; ++i) {
cout << dp[queries[i]] << " ";
}
cout << endl;
return 0;
}
这个算法的时间复杂度为 O(n2),其中n是格子的数量。对于较大规模的数据可能会比较耗时,但在题目给定的数据规模内可以满足要求。
思路如下:
定义一个数组 dp,其中 dp[i] 表示从第 i 个格子跳到第 n 个格子后方最少需要踩的格子数。
初始化 dp[n] = 0,因为已经在目标位置。
从后往前遍历每个格子,对于每个格子 i,尝试从 i + 1 到 i + a[i] 的格子中找到最小的 dp 值,并加上 1 作为从格子 i 出发的最小步数。
最后,对于每个查询的起始格子,输出对应的 dp 值。