Nearest Opposite Parity(反向建边+spfa)

You are given an array aa consisting of nn integers. In one move, you can jump from the position ii to the position i−aii−ai (if 1≤i−ai1≤i−ai) or to the position i+aii+ai (if i+ai≤ni+ai≤n).

For each position ii from 11 to nn you want to know the minimum the number of moves required to reach any position jj such that ajaj has the opposite parity from aiai (i.e. if aiai is odd then ajaj has to be even and vice versa).

Input
The first line of the input contains one integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the number of elements in aa.

The second line of the input contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤n1≤ai≤n), where aiai is the ii-th element of aa.

Output
Print nn integers d1,d2,…,dnd1,d2,…,dn, where didi is the minimum the number of moves required to reach any position jj such that ajaj has the opposite parity from aiai (i.e. if aiai is odd then ajaj has to be even and vice versa) or -1 if it is impossible to reach such a position.

Example
Input
10
4 5 7 6 7 5 4 4 6 4
Output
1 1 1 2 -1 1 1 3 1 1
思路:一开始以为是记忆化搜索,就dfs,结果成环的情况不能处理。这种题目,一般进行转化,将这些数字建成图来处理。我们建立一个超级偶数源点和一个超级奇数源点,分别连接偶数点和奇数点。
对于建边操作,我们要反向建边。为什么要反向建边呢?我们反向建边后,拿超级偶数源点来说,我们跑最短路,dis[i]代表的是这个源点到i点的最短路,反过来说也就是i到超级源点的最短路。我们取奇数点记录dis[i],这样一来,就可以找到每一个奇数点离它最近的偶数点了。如果我们正向建边,dis[i]代表的是这个源点到i点的最短路,但是不能代表i点到源点的最短路。这样就不能记录dis[i]了。因此我们要反向建边,建边后跑两次最短路就可以了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define inf 1e9
using namespace std;

const int maxx=2e6+100;
struct edge{
	int to;
	int next;
}e[maxx<<1];
int dis[maxx],vis[maxx],ans[maxx];
int a[maxx],head[maxx<<1];
int n,tot=0;

inline void add(int u,int v)
{
	e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
inline void spfa(int u)
{
	for(int i=0;i<=n+2;i++) dis[i]=inf,vis[i]=0;
	dis[u]=0;
	vis[u]=1;
	queue<int> q;while(q.size()) q.pop();
	q.push(u);
	while(q.size())
	{
		int v=q.front();
		q.pop();
		vis[v]=0;
		for(int i=head[v];i!=-1;i=e[i].next)
		{
			int to=e[i].to;
			if(dis[to]>dis[v]+1)
			{
				dis[to]=dis[v]+1;
				if(vis[to]==0)
				{
					vis[to]=1;
					q.push(to);
				}
			}
		}
	}
	
}
int main()
{
	scanf("%d",&n);tot=0;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	memset(head,-1,sizeof(head));
	for(int i=1;i<=n;i++)
	{
		if(i+a[i]<=n) add(i+a[i],i);
		if(i-a[i]>=1) add(i-a[i],i);
		if(a[i]%2==0) add(n+1,i);
		else add(n+2,i);
	}
	spfa(n+1);//偶数源点跑最短路
	for(int i=1;i<=n;i++) if(a[i]%2==1) ans[i]=dis[i];
	spfa(n+2);//奇数源点跑最短路
	for(int i=1;i<=n;i++) if(a[i]%2==0) ans[i]=dis[i];
	for(int i=1;i<=n;i++) cout<<(ans[i]==inf?-1:(ans[i]-1))<<" ";
	cout<<endl;
	return 0;
}
/*10
3 3 3 1 1 1 2 3 4 6*/

努力加油a啊,(o)/~

发布了414 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/starlet_kiss/article/details/104198024