洛谷p4779单源最短路径 使用Dj算法

题目描述

给定一个 n 个点,m 条有向边的带非负权图,请你计算从 s 出发,到每个点的距离。

数据保证你能从 𝑠s 出发到任意点。

输入格式

第一行为三个正整数 n,m,s。 第二行起 m 行,每行三个非负整数 ui​,vi​,wi​,表示从 ui​ 到 vi​ 有一条权值为 wi​ 的有向边。

输出格式

输出一行 n 个空格分隔的非负整数,表示 s 到每个点的距离。

输入输出样例

输入 

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

输出 

0 2 4 3

说明

1≤𝑛≤1051≤n≤105;

1≤𝑚≤2×1051≤m≤2×105;

𝑠=1s=1;

1≤𝑢𝑖,𝑣𝑖≤𝑛1≤ui​,vi​≤n;

0≤𝑤𝑖≤1090≤wi​≤109,

0≤∑𝑤𝑖≤1090≤∑wi​≤109。

  • 题目链接:

    P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)



  • 题目思路

  • 最短路径----Dijkstra算法

  • 什么是Dijkstra:

    本质上是一个贪心算法,有点类似于prim算法,都是从一个给定顶点开始,将每个点连接的边记录,同时更新下一节点到达原点的距离,直到所有的边都遍历过。

  • Dijkstra的堆优化

    在遍历每个点时,将与这个点相连的边都放入一个小根堆维护,保证每次弹出的都是最边(注意不考虑遍历过的点)

  • Dijkstra的流程

    我们将所有点分为两种一个称为白点,一个为黑点,白点表示未被记录过的,黑点表示记录过。

    将初始点的距离dis[s] = 0,其他点都为无穷。

    找到dis最小的值并将其改为黑点。

    遍历节点x所连接的点y,权值为w,若dis[y] > dis[x] + w,同时点y是白点是,更新dis[y] 的值

    重复上述操作直到所有的点都为黑点。

  • #include<iostream>
    #include<queue>
    #define MAX 1e9   
    using namespace std;
    long long int n, m, s;
    typedef struct {
    	long long int next, to, val;
    }node;
    long long int cnt = 1, dis[100005], vis[100005];
    node edge[200005];
    long long int head[100005];
    void add_edge(long long int u, long long int v, long long int w) //链式前向星建图
    {
    	edge[cnt].val = w;
    	edge[cnt].to = v;
    	edge[cnt].next = head[u];
    	head[u] = cnt++;
    }
    typedef pair<long long int, long long int>pll;					//第一个为边,第二为原点到此点的距离
    priority_queue<pll, vector<pll>, greater<pll>>q;				//建立优先队列
    int main()
    {
    	cin >> n >> m >> s;
    	for (int i = 0; i < m; i++) {
    		long long int  u, v, w;
    		cin >> u >> v >> w;
    		add_edge(u, v, w);
    	}
    	fill(dis + 1, dis + n + 1, MAX);				//将离第一个点的每个距离设为无穷
    	dis[s] = 0;										//将第一个设为0
    	q.push(make_pair(0, s));
    	while (!q.empty()) {
    		int x = q.top().first; int y = q.top().second;
    		q.pop();
    		if (vis[y]) continue;						//如果此点先前以被弹出,则不必理会重复先前操作 
    		vis[y] = 1;
    		for (int i = head[y]; i != 0; i = edge[i].next) {
    			if (dis[edge[i].to] > dis[y] + edge[i].val && vis[edge[i].to] == 0) {//如果离原点的距离更小,同时满足没有被弹出的节点,则更新长度
    				dis[edge[i].to] = dis[y] + edge[i].val;
    				q.push(make_pair(dis[edge[i].to], edge[i].to));			//将没有弹出过的节点加入队列
    			}
    		}
    	}
    	for (int i = 1; i <= n; i++) {
    		cout << dis[i] << ' ';
    	}
    	return 0;
    }

最后代码提交:

  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值