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;
}
相关文章
相关标签/搜索