-
题意:
一个长度为 n 的序列,每个位置可以跳到 i − a i 和 i + a i i-a_i 和 i+a_i i−ai和i+ai,求出每个位置最少需要跳几次,可以使起始位置
和结束位置
的奇偶性不同
。 -
题解:
- 反向建边,先找到起始点(即只需跳一次即可到达的),每次由花费最少且未访问过的边继续拓展。
- 不能使用
记忆化搜索
,因为内部存在环
。 - 可以不使用
优先队列
,因为权值相同,使用普通队列
即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn];
int ans[maxn];
queue<int> q;
vector<int> u[maxn];
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (i - a[i] >= 1) u[i - a[i]].emplace_back(i);//反向建边
if (i + a[i] <= n) u[i + a[i]].emplace_back(i);
}
for (int i = 1; i <= n; i++)
{
if ((i - a[i] >= 1 && (a[i] & 1) ^ (a[i - a[i]] & 1)) ||
(i + a[i] <= n && (a[i] & 1) ^ (a[i + a[i]] & 1)))
ans[i] = 1, q.push(i); //寻找起始点
}
while (!q.empty())
{
int id = q.front();
q.pop();
for (auto v : u[id])
{
if (ans[v] == 0)
{
ans[v] = ans[id] + 1;
q.push(v);
}
}
}
for (int i = 1; i <= n; i++)
{
if (ans[i]) cout << ans[i] << ' ';
else cout << -1 << ' ';
}
return 0;
}