蓝桥杯——最短路

本文介绍了如何在存在负权边的有向图中,利用SPFA(Shortest Path Faster Algorithm)算法求解从1号顶点到其他顶点的最短路径。样例展示了算法的应用,并给出了数据规模和约束条件。

问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。

输入格式
第一行两个整数n, m。

接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。

输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。

对于30%的数据,n <= 5,m <= 10。

对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。

主要算法:因为涉及到负权值,Dijkstra算法没法用了。所以用了最短路径快速算法(spfa算法)。spfa算法:开辟一个数组d用于储存到各点的距离,d[1]=0(初始点为第一个节点),到其余节点的距离为无穷大。初始化队列,将起始节点加入队列中。当队列非空时,进行如下操作:从队列里弹出一个元素,更改起始点到该元素可到达顶点的距离,如果更改成功,并且队列里没有被更改的节点,则将被更改的节点进入队列。

#include<stdio.h>
#include<malloc.h>
#define MAXN 21000
#define INF 65535
t
### 回答1: 题目要求确定一个顶点,画出有向图(其中某些边权可能为,但保证没有)。请你计算从1号点到其他点的短路(顶点从1到n编号)。 回答: 这是一道关于有向图短路的问题,题目要求确定一个顶点,画出有向图,并计算从1号点到其他点的短路。在图中可能存在一些边的权值是数,但保证不存在。 要解决这道题,我们可以使用Dijkstra或者Bellman-Ford算法。其中Dijkstra算法的时间复杂度为O(nlogn),适用于边数较少的情况;Bellman-Ford算法的时间复杂度为O(nm),适用于边数较多,权值可为的情况。 具体步骤为,先将1号点到其他点的距离初始化为无穷大,然后将1号点的距离设为0。接着,使用Dijkstra或者Bellman-Ford算法求出从1号点到其他点的短路后,输出每个点到1号点的距离即可。 注意,Dijkstra算法只适用于边权值为正的图,所以在该算法中需要将权边忽略;而Bellman-Ford算法可以处理权边,但需要注意防止的出现。 ### 回答2: 题目描述: 给定一个n个顶点,m条边的有向图(其中某些边权可能为,但保证没有)。请你计算从1号点到其他点的短路(顶点从1到n编号)。 解题思路: 该问题可以使用Dijkstra算法或者Bellman-Ford算法来求解。Dijkstra算法适用于无权边的图,时间复杂度为O(n2)或O(mlogn),Bellman-Ford算法适用于有权边的图,时间复杂度为O(nm)或O(mnlogn)。 Dijkstra算法的思路是:从起点开始,每次选择当前距离起点近的未确定节点,然后以它为中转点更新与它相邻的节点的距离。该算法需要用到一个优先队列来管理当前距离起点近的未确定节点,同时还需要用到一个数组来记录每个节点到起点的距离和是否已确定。 Bellman-Ford算法的思路是:对于每个节点,初始化它到起点的距离为无穷大,只有起点到起点的距离为0。然后进行n-1轮迭代,每轮迭代中遍历每条边,如果可以通过它缩短到某个节点的距离,则更新该节点到起点的距离。在迭代过程中,如果某个节点在第n轮迭代后仍然可以被更新,则说明存在。 综上所述,根据问题中给定的条件,应使用Bellman-Ford算法来解决。由于题目保证没有,所以只需要进行n-1轮的迭代即可。具体算法实现如下: 1. 对于每个节点i,初始化dis[i]为无穷大,只有dis[1]=0; 2. 进行n-1轮迭代,每轮遍历所有m条边,对于每条边(u,v,w),如果dis[v]>dis[u]+w,则更新dis[v]=dis[u]+w; 3. 如果在第n轮迭代中仍然有节点的dis值被更新,则说明存在。 代码实现: ```python INF = float('inf') def bellmanFord(n, m, edges): # 初始化 dis 数组,表示起点到各个节点的距离 dis = [INF] * n dis[0] = 0 # 进行 n-1 轮迭代 for i in range(n-1): # 遍历所有边 for j in range(m): u, v, w = edges[j] # 如果能通过边(u,v,w)缩短dis[v],则更新dis[v] if dis[v-1] > dis[u-1] + w: dis[v-1] = dis[u-1] + w # 判断是否存在 for j in range(m): u, v, w = edges[j] if dis[v-1] > dis[u-1] + w: return "存在" return dis ``` 其中n表示顶点个数,m表示边数,edges是一个由(m,3)的二维列表,表示边的信息,例如edges[i][0]表示第i条边的起点,edges[i][1]表示第i条边的终点,edges[i][2]表示第i条边的权值。函数返回一个长度为n的列表,表示起点到各个节点的距离,如果存在,则返回"存在"。 ### 回答3: 该问题可以使用Dijkstra算法或Bellman-Ford算法求解。 Dijkstra算法适用于所有边权为正的图,它基于贪心算法思想,每次选择距离源点近的点加入短路径集合中,并更新其它点到源点的距离。可以用小根堆优化,时间复杂度为O(mlogn)。 Bellman-Ford算法则可以处理部分边权的情况,它基于动态规划思想,逐渐更新短路径长度,直至所有短路径长度固定。该算法需要进行n-1轮松弛操作,每轮对所有边进行一次松弛,时间复杂度为O(nm)。 细节上,Dijkstra算法需要在堆中存储每个节点到源点的距离,而Bellman-Ford算法需要存储每个节点到源点的短路径长度和前驱节点。 对于本问题,由于没有,因此可以选择使用Dijkstra算法求解,时间复杂度为O(mlogn)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值