E. Nearest Opposite Parity_反向建圖+超級源點
阿新 • • 發佈:2022-05-11
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 。
但是仔細一想,我們要的只是{偶數點到奇數點,奇數點到偶數點}兩種情況,那麼分別將超級源點和奇數偶數點相連即可。
比較好玩的題目