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 。
但是仔细一想,我们要的只是{偶数点到奇数点,奇数点到偶数点}两种情况,那么分别将超级源点和奇数偶数点相连即可。
比较好玩的题目

浙公网安备 33010602011771号