CodeForces - 1196F K-th Path(最短路+思维)好题
題目鏈接:點擊查看
題目大意:給出一個 n 個點,m 條邊的無向圖,需要求出圖中第 k 短的路徑
題目分析:k 是 400,本來以為是需要思考 k * n 或 k * m 的算法,搞了半天最后原來是 k^3 的算法。。
首先考慮,先把圖中前 k 小的邊全部拿出來,比較顯然的是,答案最壞也不可能超過第 k 小的這條邊
然后對于這 k 條邊涉及到的 2 * k 個點單獨拎出來跑弗洛伊德,然后將 k * ( k - 1 ) / 2 條路徑的權值排個序求第 k 小就是答案了
妙啊
2020.12.3UPDATE:
用bfs也可以做,昨天想到用bfs了,只不過不會對路徑判重,今天看題解受到啟發,可以將無向邊拆成兩條有向邊,然后求第 2 * k 小的路徑即是答案
興致勃勃寫了一發 n * k * logn 的算法,交上去 MLE 了,說明暴力擴展是不太合適的,所以考慮優化
可以將鄰接表中的所有鄰邊按照權值排序,并且對于每條邊來說,之前記錄的是 ( st , ed ),現在我們需要記錄一個中間點 x,也就是 ( st , x , ed ),滿足最后一條邊是 x -> ed,這樣還看不出來有什么好處,但是我們實際上記錄的是 ( st , x , index ),index 指的是 x 的鄰接表中的第 index 個元素,自然可以表示出 ed 了,并且還有一個最大的好處就是,在擴展的時候,將 st -> x -> index 這條邊撤回,改成 st -> x -> index+1 一定是最優的,所以擴展狀態的時候就有兩種途徑了:
因為每次只擴展兩個狀態,所以 bfs 的復雜度是 O( n ) ,因為需要對每條邊排序,所以總時間復雜度是 O( nlogn ) 的
代碼:
Floyd:
bfs:
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Node {int st,ed,id;LL w;bool operator<(const Node& t)const{return w>t.w;} };set<pair<int,int>>vis;//st,edvector<pair<int,int>>node[N];priority_queue<Node>q;int main() { #ifndef ONLINE_JUDGE // freopen("data.ans.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n,m,k;scanf("%d%d%d",&n,&m,&k);while(m--){int u,v,w;scanf("%d%d%d",&u,&v,&w);node[u].emplace_back(w,v);node[v].emplace_back(w,u);}for(int i=1;i<=n;i++){sort(node[i].begin(),node[i].end());q.push({i,i,0,node[i][0].first});vis.emplace(i,i);}k*=2;while(q.size()){auto cur=q.top();q.pop();if(cur.id+1<node[cur.ed].size())q.push({cur.st,cur.ed,cur.id+1,cur.w-node[cur.ed][cur.id].first+node[cur.ed][cur.id+1].first});if(vis.count(make_pair(cur.st,node[cur.ed][cur.id].second)))continue;vis.emplace(cur.st,node[cur.ed][cur.id].second);if(--k==0)return 0*printf("%lld\n",cur.w);q.push({cur.st,node[cur.ed][cur.id].second,0,cur.w+node[node[cur.ed][cur.id].second][0].first});}return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 1196F K-th Path(最短路+思维)好题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 336D Va
- 下一篇: CodeForces - 137D Pa