单源最短路径 Dijkstra 算法


Dijkstra

Dijkstra算法流程

1.初始化 dist[1]=0,其余节点的 d i s t dist dist 值为正无穷大。
2.找出未标记的、 d i s t [ x ] dist[ x ] dist[x]最小的节点 x x x ,然后标记节点 x x x
3.扫描节点 x x x的所有出边 ( x , y , z ) (x,y,z) (x,y,z),若 d i s t [ y ] dist[ y ] dist[y] > d i s t [ x ] dist[ x ] dist[x] + z z z,则 d i s t [ y ] dist[ y ] dist[y] = d i s t [ x ] dist[ x ] dist[x] + z z z
4.重复上述 2~3 两个步骤,直到所有的节点都被标记 。

迪杰斯特拉算法不能处理存在负权的图,当权值是非负时,全局最小值不可能再被其他节点更新,所以在第 1 1 1 步选出的节点 x x x 肯定满足: d i s t [ x ] dist[ x ] dist[x] 已经是起点到 x x x 的最短路径。不断选择全局最小值进行标记和扩展,最终可得到起点 1 到每个节点的最短路径的长度。

邻接表

加入有向边 ( u , v ) (u,v) (u,v),权值为 k k k

void Add(int u,int v,int k)
{
	edge[++tot].val=k;
	edge[tot].to=v;
	edge[tot].next=head[u];
	head[u]=tot;
}

访问从 u 出发的所有边

for(int i=head[u];i;i=edge[i].next)  // -1取反是 0
{
    int v=edge[i].to;
	int val=edge[i].val;
	if(dist[v]>dist[u]+val)  //更新最短路径
	{
		dist[v]=dist[u]+val;
		pre[v]=u;
		p.push(PII(dist[v],v));
	}
}

Dijkstra

题目大意
You are given a weighted undirected graph. The vertices are enumerated from 1 to n. Your task is to find the shortest path between the vertex 1 and the vertex n.
Input
The first line contains two integers n and m (2 ≤  n n n ≤  1 0 5 10^5 105, 0 ≤  m m m ≤  1 0 5 10^5 105), where n n n is the number of vertices and m m m is the number of edges. Following m m m lines contain one edge each in form a i a_i ai, b i b_i bi and w i w_i wi (1 ≤  a i a_i ai,  b i b_i bi ≤ n, 1 ≤  w i w_i wi ≤  1 0 6 10^6 106), where a i a_i ai,  b i b_i bi are edge endpoints and w i w_i wi is the length of the edge.
It is possible that the graph has loops and multiple edges between pair of vertices.
Output
Write the only integer -1 in case of no path. Write the shortest path in opposite case. If there are many solutions, print any of them.
输入样例

5 6
1 2 2
2 5 5
2 3 4
1 4 1
4 3 3
3 5 1

输出样例

1 4 3 5

题解

给你一个无向图,给你 n n n 个点, m m m条边,询问从1~ n n n是否存在单源最短路径,如果存在,请输出路径,如果不存在,请输出-1
无向图空间开两倍,爆 l o n g long long l o n g long long 0 x 3 f 3 f 3 f 3 f 0x3f3f3f3f 0x3f3f3f3f i n t int int类型的最大值,所以这里的无穷大应该取 1 e 18 1e^{18} 1e18多一点,开个 p r e [ ] pre[] pre[] 数组记录最短路径的走向,最后看是否存在单源最短路径,如果存在,输出 p r e [ ] pre[] pre[] 数组的内容,如果不存在,就输出 - 1 1 1

#include <bits/stdc++.h>
#define pb push_back
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e5 + 20;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;
typedef pair<int,int> PII;
int n,m;
int tot;
int head[maxn];
struct Node{
	int to;
	ll val;
	int next;
}edge[maxn<<1];
ll dist[maxn];
bool vis[maxn];
int pre[maxn];
int ans[maxn];
void Add(int u,int v,int k)
{
	edge[++tot].val=k;
	edge[tot].to=v;
	edge[tot].next=head[u];
	head[u]=tot;
}
void Dijkstra(int s)
{
    for(int i=1;i<=n;++i) dist[i]=INF;
	memset(vis,0,sizeof(vis));
	dist[s]=0;
	priority_queue<PII,vector<PII>,greater<PII> > p;
	p.push(pair<int,int>(0,s));
	while(p.size())
	{
		PII temp=p.top();
		p.pop();
		int u=temp.second;
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=edge[i].next)
		{
			int v=edge[i].to;
			int val=edge[i].val;
			if(dist[v]>dist[u]+val)
			{
				dist[v]=dist[u]+val;
				pre[v]=u;
				p.push(PII(dist[v],v));
			}
		}
	}
} 
int main()
{
	scanf("%d %d",&n,&m);
    memset(head,-1,sizeof(head));
    for(int i=0;i<m;i++)
    {
        int x,y,z;
        scanf("%d %d %d",&x,&y,&z);
        Add(x,y,z);
        Add(y,x,z);
    }
    Dijkstra(1);
    if(dist[n]==INF) printf("-1\n");
    else
    {
        int t=n,idx=0;
        while(t!=1)
        {
            ans[++idx]=t;
            t=pre[t];
        }
        ans[++idx]=1;
        for(int i=idx;i;i--) printf("%d ",ans[i]);
    }
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

幸愉聊信奥

谢谢亲的支持,我会继续努力啦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值