dijkstra

\(dijkstra​\)怎麼寫:首先,是和\(SPFA​\)同樣的初始化。而後,把起點標記爲訪問。而後更新與其相連的點的最短路的值(就是鬆弛)。再找到未訪問的點中最短路的值最小的點,重複以上操做。
具體實現起來就是這個亞子:

(圖片來源於洛谷2019夏令營的課件)
講完基礎的,再來說一下細節問題:這個細節決定了時間複雜度
這個細節就是「找到未訪問的點中最短路的值最小的點」。
兩種方法:
第一種:很是實用的爆掃。時間複雜度是O(\(n^2​\)),我的感受和\(SPFA​\)沒有什麼區別,不建議使用。
第二種:優先隊列!該方法是當一個點的最短路的值被更新後,就將其加入小根堆。這時小根堆裏會出現多個相同的點。可是咱們用過一個點以後就會將其標記,因此不會有問題。時間複雜度是O(mlogn)
什麼?你不知道小根堆是什麼?戳這裏
但咱們是不會手打小根堆的,太麻煩了。因而,咱們就要用到priority_queue。他是系統自帶優先隊列,可是是大根堆。並且咱們是要按照每一個點的值來排序的。但咱們同時也要記錄他的編號。node

因而能夠這樣搞:spa

struct node
{
	int first,second;
	friend bool operator<(node x,node y){return x.first>y.first;}
};
priority_queue<node> q;

全部問題都解決了,那麼上代碼吧。code

#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,s;
int v[100005];
bool f[100005];
struct node
{
	int first,second;
	friend bool operator<(node x,node y){return x.first>y.first;}
};
priority_queue<node> q;
struct graph
{
	int tot;
	int hd[100005];
	int nxt[200005],to[200005],dt[200005];
	void add(int u,int v,int w)
	{
		tot++;
		nxt[tot]=hd[u];
		hd[u]=tot;
		to[tot]=v;
		dt[tot]=w;
		return ;
	}
}g;
int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		g.add(u,v,w);//建圖
	}
	memset(v,0x3f,sizeof(v));//初始化
	q.push((node){0,s});//壓入起點
	v[s]=0;
	while(!q.empty())
	{
		int xx=q.top().second;
		q.pop();
		if(!f[xx])//判斷是否被訪問過
		{
			f[xx]=true;//標記一下
			for(int i=g.hd[xx];i;i=g.nxt[i])
				if(v[g.to[i]]>v[xx]+g.dt[i])//鬆弛
		 		{
					v[g.to[i]]=v[xx]+g.dt[i];
					q.push((node){v[g.to[i]],g.to[i]});//加入小根堆
				}
		}
	}
	for(int i=1;i<=n;i++) printf("%d ",v[i]);
	return 0;
}
相關文章
相關標籤/搜索