P4779 【模板】單源最短路徑(標準版) 題解

博客園同步

原題鏈接

簡要題意:

給定一個有向圖,求從源點開始到各點的最短路。

前置知識:

P3371 【模板】單源最短路徑(弱化版)

首先,我們考慮把原來 Dijkstra\text{Dijkstra} 的算法考慮優化。

對於每個節點,鬆弛相鄰節點,這部分無法優化。

但是尋找 dis\text{dis} 最小值的過程,我們可以用 優先隊列(即小根堆)實現

怎麼實現呢?

考慮一開始源點入隊,隊列記錄每個點的 當前 dis\text{dis} 最小值 和編號。

對當前節點,把所有相鄰的節點鬆弛一遍,並把鬆弛成功的節點入隊。

但是你發現一個問題,如果一個點被它相鄰的點同時更新多次,就會入隊多次,然後把一模一樣的鬆弛進行很多遍,然後 O(n2)O(n^2) 沒了。

所以 因爲我們開的是優先隊列,因此入隊的節點距離小的在前,每次對於相同的一個節點,先遍歷的一定最優。因此可以開一個哈希記錄是否走過,走過則不走即可。

時間複雜度:O(nlogn)O(n \log n).

實際得分:O(100pts)O(100pts).

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

const int N=2e5+1;

inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}

priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
int n,m,s,dis[N]; bool vis[N];
vector<pair<int,int> > G[N];

inline void Dijkstra(int s) {
	dis[s]=0; q.push(make_pair(0,s));
	while(!q.empty()) {
		int x=q.top().second;
		q.pop(); if(vis[x]) continue; vis[x]=1; //判斷哈希
//		printf("%d\n",x);
		for(int i=0;i<G[x].size();i++) {
			int v=G[x][i].first,w=G[x][i].second;
			if(dis[v]>dis[x]+w) {
				dis[v]=dis[x]+w;
				if(!vis[v]) q.push(make_pair(dis[v],v)); //鬆弛入隊
			}
		}
	}	
}

int main(){
	n=read(),m=read(),s=read();
	memset(dis,0x3f,sizeof(dis));
	while(m--) {
		int u=read(),v=read(),w=read();
		G[u].push_back(make_pair(v,w));
	} Dijkstra(s);
	for(int i=1;i<=n;i++) printf("%d ",dis[i]); puts(""); 
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章