E. Nearest Opposite Parity_反向建图+超级源点

E. Nearest Opposite Parity_反向建图+超级源点

题目大意

给数列a,ai表示存在(i,i-ai)和(i,i+ai)两条边。每条边边权为1。现在要求出以ai出发到aj(ai和aj满足奇偶性不同的条件)的所有路径中最短的长度。

思路和代码

超级源点模板题

首先建立两个超级源点。分别代表从奇数出发从偶数出发

再反向建图,这样dsi的含义就变成到达点i所需要的最短路径,而不是常规最短路问题中的dsi表示从起点到i的最短路径。

再分别做一次最短路(可以dij也可以bfs啥的)

然后把从奇数点出发的填入偶数位置,把从偶数点出发的填入奇数位置。

int n , m , k ; 

void dij(int s , vct<ll> &ds , vct<vct<pii> > &eg){
	rep(i , 0 , n + 1) ds[i] = INF ;
	vct<bool> vis(n + 2 , 0) ;
	
	priority_queue<pll , vct<pll> , greater<pll> > hp ;
	hp.push({0 , s}) ;
	ds[s] = 0 ;
	
	while(hp.size()){
		int now = hp.top().se ;
		int dis = hp.top().fi ;
		hp.pop() ;
		if(vis[now]) continue ;
		vis[now] = 1 ;
//		cout << now << "\n" ;
		for(pii e : eg[now]){
			int nxt = e.se ;
			int len = e.fi ;
			if(ds[nxt] > ds[now] + len){
				ds[nxt] = ds[now] + len ;
				hp.push({ds[nxt] , nxt}) ;
			}
		}
	}
}

void solve(){
	
	cin >> n ;
	vct<int> a(n + 1 , 0) ;
	vct<vct<pii> > eg(n + 2) ;
	
	rep(i , 1 , n){
		cin >> a[i] ;
		if(a[i] % 2 == 1) eg[0].pb({0 , i}) ;
		else  eg[n + 1].pb({0 , i}) ;
		//0为奇数起点 , n+1为偶数起点
		if(i + a[i] <= n) eg[i + a[i]].pb({1 , i}) ;

		if(i - a[i] >= 1) eg[i - a[i]].pb({1 , i}) ;
	}

	vct<ll> ds(n + 2 , INF) ;
	
	vct<ll> ans(n + 1 , -1) ;
	
	dij(0 , ds , eg) ;
	
	rep(i , 1 , n)
	if(a[i] % 2 == 0){//奇数点要到偶数点
		if(ds[i] >= INF) continue ;
		ans[i] = ds[i] ;
	}
	
	dij(n + 1 , ds , eg) ;

	rep(i , 1 , n)
	if(a[i] % 2){//偶数点要到奇数点
		if(ds[i] >= INF) continue ;
		ans[i] = ds[i] ;
	}
		
	show1(ans , 1 , n) ;
	
}//code_by_tyrii 

小结

关于这一题我一开始想成了将所有点都和超级源点相连,但是这样就会导致所有点的ds值都是0 。

但是仔细一想,我们要的只是{偶数点到奇数点,奇数点到偶数点}两种情况,那么分别将超级源点和奇数偶数点相连即可。

比较好玩的题目

posted @ 2022-05-11 15:59  tyrii  阅读(95)  评论(0)    收藏  举报