*牛妹遊歷城市【最短路建虛點】
阿新 • • 發佈:2020-08-16
題意
題目連結:https://ac.nowcoder.com/acm/contest/6885/E
分析
如果直接建邊,肯定會超時。那麼,就要進行轉化。可以設定 \(32\) 個虛點,分別表示點權的第 \(i\) 位為 \(1\)。對於點權 \(a[i]\) 如果其第 \(j\) 位為 \(1\),那麼就從該點連一條權值為 \(2^j\) 的邊到對應的虛點,並建立一條權值為 \(0\) 的反向邊。最後跑一遍最短路即可。
證明:對於一個點,按照最短路的貪心策略,必然會選擇與之相連的權值最小的出邊,這樣剛好滿足了題目建邊的原則。並且,通過虛邊,可以使得兩點是按 \(lowbit\) 建邊。
程式碼
#include <bits/stdc++.h> #define pb push_back using namespace std; typedef long long ll; typedef pair<ll,int>pli; const int N=1e5+100; const ll inf=1e18; ll dis[N]; int n; vector<pli>pic[N]; priority_queue<pli,vector<pli>,greater<pli> > que; void addedge(int u,ll w) { for(int i=0;i<32;i++) { if((w>>i)&1) { pic[u].pb(make_pair((1LL<<i),i)); pic[i].pb(make_pair(0,u)); } } } void dij() { for(int i=0;i<=n+32;i++) dis[i]=inf; while(!que.empty()) que.pop(); dis[33]=0; que.push(make_pair(0,33)); while(!que.empty()) { pli now=que.top(); que.pop(); if(dis[now.second]<now.first) continue; for(int i=0;i<pic[now.second].size();i++) { pli tmp=pic[now.second][i]; if(dis[tmp.second]>dis[now.second]+tmp.first) { dis[tmp.second]=dis[now.second]+tmp.first; que.push(make_pair(dis[tmp.second],tmp.second)); } } } } int main() { int T; scanf("%d",&T); while(T--) { ll a; scanf("%d",&n); for(int i=0;i<=n+32;i++) pic[i].clear(); for(int i=1;i<=n;i++) { scanf("%lld",&a); addedge(i+32,a); } dij(); if(dis[n+32]==inf) printf("Impossible\n"); else printf("%lld\n",dis[n+32]); } return 0; }
題解:https://blog.nowcoder.net/n/13d05ab8ac22444a81fbe475de2f563e