BNDSOJ #1051-Easy SSSP题解——负环的判断与spfa算法中的数据维护

开头说的一些话

大家所想要的sightseeing trip正在研究,预计一周更新。今天的题目前班里AC的人加上我一共只有6个大概是班里人数的1/3,但是从我个人看来这一道模板题还是具有一定的典型性的,特此更新今日的题解。
注:为了方便阅读,本文中的0x3f泛指无穷大,即int形的0x3f3f3f3f(4个3f)

正文

题目

输入数据给出一个有 N 个节点,M 条边的带权有向图。要求你写一个程序,判断这个有向图中是否存在负权回路。如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于 0,就说这条路是一个负权回路。
如果存在负权回路,只输出一行 -1;如果不存在负权回路,再求出一个点 S 到每个点的最短路的长度。约定:S 到 S 的距离为 0,如果S 与这个点不连通,则输出 NoPath。

输入、输出数据和范例

输入:第一行三个正整数,分别为点数 N,边数 M,源点 S;
以下 M 行,每行三个整数 a, b, c,表示点 a, b 之间连有一条边,权值为 c。
输出:如果存在负权环,只输出一行 -1,否则按以下格式输出:
共 N 行,第 i 行描述 S 点到点 i 的最短路:
如果 S 与 i 不连通,输出 NoPath; 如果 i = S,输出 0。 其他情况输出 S 到 i 的最短路的长度。
样例输入:
6 8 1
1 3 4
1 2 6
3 4 -7
6 4 2
2 4 5
3 6 3
4 5 1
3 5 4
样例输出:
0
6
4
-3
-2
7

我个人的思考方向

众所周知,如果一个图里面存在负环,那么很大可能(记住,是很大可能,不是绝对)上这个图的全部或部分节点到源点是不存在最短路径的。距离可以无限小,松弛操作可以进行无限次。
对于这道题而言,题目的要求是只要有负环就要输出-1 。注意这里的-1可不是算法在求距离的时候遇到了负环才算负环的。如我自己出的下面一套数据,存在负环,但是按照一般SPFA是发现不了的(如果像我一样0x3f在松弛过程中没有被减的话)

5 4 1
2 3 -1
3 4 -1
4 5 -1
5 2 -1

如果我们用SPFA处理源点不能够到达的负环并且对于0x3f也和一般距离数据一样逐步往下减的话,我们其实也能找出源点所不能够达到的负环。但是,在dis数组中所认为的到达该点的距离也会跟着往下减。这样一来对我们最后是否输出为"no path"进行判定时就会遇到很大的麻烦——空凭数据我们可能无法知道我们的距离数据到底是从0x3f减下来的还是从源点一点一点算过来的,这样的场面,不得不说,十分尴尬。
在权衡之后我选择尽量保证数组中的0x3f不被破坏,也就使我的负环判定成为了一个需要攻克的点。
现在网上对于这种问题,有一种解决方案是多次设不同的源点去SPFA。但是为我自己想出来的解决方案是另开一个源点,使这个源点能够到达所有节点并且距离都是0。这样就不会漏搜了。如果发现了负环点,我们就输出-1,结束程序
走过了这一步,我们就得到了一个保证没有你负环的图。然后的解决方法就是套一个模板的事情啦!
按照往常的规矩,放出代码的注释。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
/*
整体思路:SPFA算法,先构建一个原点保证每个节点都能够被到达,然后不断松弛
直到有一个点的入队次数大于等于节点数,如此就证明这个图存在负环,并且不存
在没有遍历到的负环的可能性。
如果没有负环,那么我们就用输入中给出的原点再进行一次SPFA,输出指定点到达
各个节点的距离。 
邻接表用在这道题里面是一个不错的选择 
*/
struct edge{
   //存储一条边 
	int from;
	int to;
	int dist;
	edge* next;
};
edge* ed[111111];//存储边的邻接表 
int dis [1001];//距离 
int dl[100000000];//SPFA队列 
int rdt[1001];//入队的次数 
int maxrdt = 0;//入队次数最多的点的入队次数 
int tail,head;//队头和队尾 
int pnum;//节点数 
int ednum;
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值