蓝桥杯 ALGO-5最短路

问题描述

给定一个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,保证从任意顶点都能到达其他所有顶点。

题意:给定一个有向图,然后求从1号节点到其他节点的最短距离,而且路径的权值中有负的权值。

思路:对于此题,主要是边的权值为负的情况,所以不能直接使用dijkstar的算法,要使用变形的,即广度优先遍历+dijstar算法也就是其他猿友说的SPFA算法,

摘录猿友的解释:

  1. 它可以在O(kE)的时间复杂度内求出源点到其他所有点的最短路径,可以处理负边。
  2. SPFA 在形式上和BFS非常类似,不同的是BFS中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进,于是再次用来改进其它的点,这样反复迭代下去。
  3. 判断有无负环:如果某个点进入队列的次数超过V次则存在负环(SPFA无法处理带负环的图)。

具体做法就是:维护一个先进先出的队列,进行深度搜索,每次队列出队首元素,然后把其邻接的点且从节点1到该节点的距离比原来小时就更新,如果该节点不在队列中就将其加入队列,且将其标识置为true,否则不做。最后打印从1到其他节点的所有距离。

代码:

#include <iostream>
#include<vector>
#include<queue> 
#define N 20010
#define INF 65536
using namespace std;
struct node{//表示从1到v节点信息 
	int v,dis;
};
int D[N], n, m;//存储图,最短路径
bool inQueue[N];//标识该点是否在队列中 
vector<node> g[N];//邻接表存储图信息 
void SPFA() {//用于计算从1到其他顶点的距离 
	fill(D, D + N, INF);
	D[1] = 0;//初始化第一个访问的点
	queue<int> q;
	q.push(1);//把第一个点加入队列 
	while(!q.empty()){
		int u = q.front();
		q.pop();
		inQueue[u]=false;//把出队列的点置为不在队列中 
		for(int i=0;i<g[u].size();i++){//更新队列第一个元素到其他节点的最短距离
		    int v = g[u][i].v,dis = g[u][i].dis;
			if(D[u]+dis<D[v]){//更新从该点到达其他节点的最短距离 
				D[v] = D[u] +dis;
				if(!inQueue[v]){//如果其邻接点不在队列中,则置为true,且加入队列中 
					inQueue[v]=true;
				    q.push(v);	
				}
			}
		}
	}
}
int main(int argc, char** argv) {
	int u, v, L;
	cin >> n >> m;
	for (int i = 0; i < m; i++) {//输入所有边和距离 
		scanf("%d%d%d", &u, &v, &L);
		g[u].push_back(node{v,L}); 
	}
	SPFA();
	for (int i = 2; i <= n; i++) {
		printf("%d\n", D[i]);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值