Codeforces 1272E Nearest Opposite Parity

关于此题:
1.咋一看,不就是无脑dfs吗。一通乱码,然后 wawawawawa。。。。。。
经过仔细思考 反反复复举例
从 【 8 : 2 2 1 3 4 5 6 7;】 发现一丝端倪。
第七个点7(6) 的路径应该为2,却跑出了-1;
在这里插入图片描述
调试以后发现问题所在:
如果dfs 第一个点的话 1(2)>3(1)>2(2)>4(3)>7(6) 当转移到第7个点的时候 ,离的6最短的奇偶性相异的点是3(1),而此时并3(1)并没有更新为最短路所以无法用来更新7(6);所以7(6)的得到的答案是错误的。。
dfs(行不通)。。
下面说下正确的解法(bfs):
如果把题当作图的话,此题可以看作每个点至多有两条权值为1的出路的单向有环图。只需bfs一轮图即可。
步骤:
1。开两个数组odd【maxn】,even[maxn]。(odd[i],表示第i个点到第一个为奇数的点的路长,even[i]为到偶数点的路长)若a[i]为奇数,则odd[i]=0。反之,even[i]=0;
2.反向存边。
3.bfs跑一轮图
4.输出结果。
(先贴一个愚蠢的dfs,引以为戒,图论题还是得用图的解法)

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <stack>
#include <bitset>
#define ll long long
using namespace std;
const int maxn=200000+10;
int n;
int a[maxn];
int dpji[maxn];
int dpou[maxn];
int vis[maxn];
void dfs(int x){
	if(vis[x])return;
	vis[x]=1;
	if(x-a[x]>=1){
		dfs(x-a[x]);
		dpji[x]=min(dpji[x],dpji[x-a[x]]+1);
		dpou[x]=min(dpou[x],dpou[x-a[x]]+1);
	}
	if(x+a[x]<=n){
		dfs(x+a[x]);
		dpji[x]=min(dpji[x],dpji[x+a[x]]+1);
		dpou[x]=min(dpou[x],dpou[x+a[x]]+1);
	}
}
int main(){
	memset(vis,0,sizeof(vis));
	cin>>n;
	for(int i=1;i<=n;i++){
		dpou[i]=200010;
		dpji[i]=200010;
	}
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]&1)dpji[i]=0;
		else dpou[i]=0;
	}
	for(int i=1;i<=n;i++){
		dfs(i);
	}
	for(int i=1;i<=n;i++){
		if(a[i]&1){
			if(dpou[i]==200010)cout<<-1<<' ';
			else cout<<dpou[i]<<' ';
		}
		else {
			if(dpji[i]==200010)cout<<-1<<' ';
			else cout<<dpji[i]<<' ';
		}
	}
	return 0;
}
BFS
```cpp
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <stack>
#include <bitset>
#define ll long long
using namespace std;
const int maxn=2e5+10;
int n;
int odd[maxn];
int even[maxn];
int vis[maxn][2];
int first[maxn];
int a[maxn];
queue<int>q[2];
struct edge{
	int to,next;
}e[maxn*2];
int tol=0;
void addedge(int v,int from){
	tol++;
	e[tol].to=v;
	e[tol].next=first[from];
	first[from]=tol;
}
void cal(){
	while(!q[0].empty()){	
		int now=q[0].front();q[0].pop();
		vis[now][0]=0;
		for (int i = first[now]; i; i=e[i].next)
		{
			if(odd[e[i].to]>odd[now]+1){
				odd[e[i].to]=odd[now]+1;
				if(!vis[e[i].to][0])q[0].push(e[i].to);
			}
		}
	}
	while(!q[1].empty()){	
		int now=q[1].front();q[1].pop();
		vis[now][1]=0;
		for (int i = first[now]; i; i=e[i].next)
		{
			if(even[e[i].to]>even[now]+1){
				even[e[i].to]=even[now]+1;
				if(!vis[e[i].to][1])q[1].push(e[i].to);
			}
		}
	}
}
int main(){
	cin>>n;
	memset(odd,0x1f,sizeof(odd));
	memset(even,0x1f,sizeof(even));
	memset(first,0,sizeof(first));
	memset(vis,0,sizeof(vis));
	for (int i=1; i<=n; i++){
		cin>>a[i];
		if(a[i]%2==1){
			odd[i]=0;
			q[0].push(i);
			vis[i][0]=1;
			if(i-a[i]>=1)addedge(i,i-a[i]);
			if(i+a[i]<=n)addedge(i,i+a[i]);
		}
		else {
			even[i]=0;
			q[1].push(i);
			vis[i][1]=1;
			if(i-a[i]>=1)addedge(i,i-a[i]);
			if(i+a[i]<=n)addedge(i,i+a[i]);
		} 
	}
	cal();
	for(int i=1;i<=n;i++){
		if(a[i]&1){
			if(even[i]==0x1f1f1f1f)cout<<-1;
			else cout<<even[i];
		}
		else{
			if(odd[i]==0x1f1f1f1f)cout<<-1;
			else cout<<odd[i];
		}
		cout<<' ';
	}
	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值