【模板】单源最短路径(Dijkstra算法)

前往:我自己搭建的博客

题目

洛谷P4779【模板】单源最短路径(标准版)

题解

链式前向星(存边结构):与链表的结构和查找遍历方式相同,唯一的不同点就是插入的位置。链式前向星每次将新的元素插入链表头。为每一个节点建立一个链表,存入此节点的所有出边。

Dijkstra算法:这个算法要求所有边的权重都为非负值。定义d[i]为从起点到第i个节点的最短路径长度。

算法流程:假设起点为s。1.令d[s]=0 ,其它d[i]为无穷大 2.从没有被标记的节点中找出d[x]最小的节点x,然后标记x 3.枚举x的所有出边x->y(边权为w) ,若d[y]>d[x]+w,则用d[x]+w更新d[y] 4.重复2、3,直到所有节点都被标记。

算法原理:基于贪心思想。每次找到的d[x]最小的节点,不可能再被较大的d[y]更新,所以d[x]必然是s~x的最短路径。

算法优化:动态维护d[x]最小值,减少查找的时间。利用STL 优先队列(大根堆),用STL pair存d[x]和x,将d[x]转成-d[x]存入,把大根堆转化成小根堆。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x7fffffff;
const int maxn=1e5+5;
const int maxm=2e5+5;
int n,m,s,c;
bool v[maxn];	//v[]表示是否标记 
int head[maxn],d[maxn];	//head[x]表示节点x的链表头 
struct edge{int to,nxt,w;}e[maxm];
inline void add(int from,int to,int w)	//加边 
{
	e[++c].to=to; e[c].w=w; e[c].nxt=head[from]; head[from]=c;
}
priority_queue<pair<int,int> > q;
inline void dijkstra()
{
	for(int i=1;i<=n;i++) d[i]=inf;
	memset(v,0,sizeof(v));	//初始化 
	d[s]=0; q.push(make_pair(0,s));
	while(q.size())
	{
		int x=q.top().second; q.pop();
		if(v[x]) continue; v[x]=1;
		for(int i=head[x];i;i=e[i].nxt)	//遍历x的所有出边 
		{
			int y=e[i].to;
			if(d[y]>d[x]+e[i].w)
			{
				d[y]=d[x]+e[i].w;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}

int main()
{
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;i++)
	{
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}
	dijkstra();
	for(int i=1;i<=n;i++) printf("%d ",d[i]);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zjgmartin/article/details/108415521