【题目描述】
小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:
对于这个问题,我们可以使用动态规划的思想来解决。
首先,我们需要定义一个长度为n的数组dp,其中dp[i]表示从第i个格子开始跳到第n个格子的最少次数。初始时,将dp[n]设为0,表示从第n个格子跳到第n个格子不需要任何次数。
然后,从第n-1个格子开始向前遍历,对于每个格子i,我们需要计算从第i个格子跳到第n个格子的最少次数。这可以通过遍历从i+1到i+a[i]的格子 j 的dp[j]值,并选取最小的值再加上1来计算。假设这个最小值为min_count,那么dp[i] = min_count + 1。
最后,对于每个询问的格子起始位置,我们可以直接查询dp数组的对应位置即可得到最少需要踩的格子数。
下面是使用Python实现的代码:
python
Copy to clipboard
n, m = map(int, input().split())
a = list(map(int, input().split()))
queries = list(map(int, input().split()))
dp = [float('inf')] * (n + 1)
dp[n] = 0
for i in range(n - 1, -1, -1):
min_count = float('inf')
for j in range(i + 1, min(i + a[i] + 1, n + 1)):
min_count = min(min_count, dp[j])
dp[i] = min_count + 1
for q in queries:
print(dp[q], end=' ')
print()
用dp考虑这个问题,用一个vector类型的 g[i] 表示有哪些点往后跳跃可以走到点 i ,设 f[i] 表示走到 i 最少走多少格子,在不考虑先走到后面再走回来的情况下,则有$f[i] = min(f[i - 1], min{f[g[i][j]]}) + 1,对于先走到后面的格子再走回来的情况,我们知道只要到了 i 后面任意一个格子就能只走1步走到 i ,因此这个过程可以被我们分为两步,首先从 i 前面的格子走1步走到 i 后面,再直接走到 i ,于是走到 i 后面的这个步骤被我们拆为从 i 前面走两步,于是便能得到转方程 f[i] = min(f[j](j + a[j]>i)+2,min(f[i - 1], min{f[g[i][j]]})+1)
这里不是很好写公式,理解一下就好
这个问题可以通过广度优先搜索(BFS)来解决。我们需要从每个询问的起始格子出发,找到最少的跳跃次数以到达第 n 个格子的后方。以下是解决这个问题的详细步骤和代码实现。
以下是 C++ 的实现代码:
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
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> results(m);
for (int q = 0; q < m; ++q) {
int start = queries[q];
vector<int> dist(n + 1, -1); // -1 means unvisited
queue<int> bfsQueue;
bfsQueue.push(start);
dist[start] = 1; // Starting from the start position
while (!bfsQueue.empty()) {
int current = bfsQueue.front();
bfsQueue.pop();
// Check if we can jump out of the last box
if (current + a[current] > n) {
results[q] = dist[current] + 1; // +1 for the jump out
break;
}
// Jump to previous boxes
for (int i = 1; i < current; ++i) {
if (dist[i] == -1) { // If not visited
dist[i] = dist[current] + 1;
bfsQueue.push(i);
}
}
// Jump to next boxes
for (int i = current + 1; i <= min(n, current + a[current]); ++i) {
if (dist[i] == -1) { // If not visited
dist[i] = dist[current] + 1;
bfsQueue.push(i);
}
}
}
}
// Output results
for (int i = 0; i < m; ++i) {
cout << results[i];
if (i < m - 1) cout << " ";
}
cout << endl;
return 0;
}
n
和询问的次数 m
,然后读取每个格子的跳跃度 a
和每个询问的起始格子。bfsQueue
来进行 BFS。dist
数组用于记录每个格子的跳跃次数,初始值为 -1(表示未访问)。这个实现能够处理题目给定的约束条件。