<—点个赞吧QwQ
宣传一下算法提高课整理
给出一个 $N$ 个顶点 $M$ 条边的无向无权图,顶点编号为 $1$ 到 $N$。
问从顶点 $1$ 开始,到其他每个点的最短路有几条。
输入格式
第一行包含 $2$ 个正整数 $N,M$,为图的顶点数与边数。
接下来 $M$ 行,每行两个正整数 $x,y$,表示有一条顶点 $x$ 连向顶点 $y$ 的边,请注意可能有自环与重边。
输出格式
输出 $N$ 行,每行一个非负整数,第 $i$ 行输出从顶点 $1$ 到顶点 $i$ 有多少条不同的最短路,由于答案有可能会很大,你只需要输出对 $100003$ 取模后的结果即可。
如果无法到达顶点 $i$ 则输出 $0$。
数据范围
$1 \\le N \\le 10^5$,
$1 \\le M \\le 2 \\times 10^5$
输入样例:
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5
输出样例:
1
1
1
2
4
思路
设$cnt_i$表示$1\sim i$的最短路数量
对于每次$\text{SPFA}$的松弛操作中的每条边$(a,b,w)$,我们分类讨论:
- 若$dist_b>dist_a+w$,则$cnt_b$应更新为$cnt_a$,因为以前的$cnt_b$不是最短路了。
- 若$dist_b=dist_a+w$,则$cnt_b$应加上$cnt_a$,因为这里的最短路长度相同
代码
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int N = 100010,M = 400010,MOD = 100003;
int n,m;
int h[N],e[M],ne[M],idx;
int dist[N],cnt[N];
bool st[N];
void add (int a,int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void spfa () {
queue <int> q;
q.push (1);
memset (dist,0x3f,sizeof (dist));
dist[1] = 0;
cnt[1] = 1;
st[1] = true;
while (q.size ()) {
int t = q.front ();
q.pop ();
st[t] = false;
for (int i = h[t];~i;i = ne[i]) {
int j = e[i];
if (dist[j] > dist[t] + 1) {
dist[j] = dist[t] + 1;
cnt[j] = cnt[t];
if (!st[j]) {
q.push (j);
st[j] = true;
}
}
else if (dist[j] == dist[t] + 1) cnt[j] = (cnt[j] + cnt[t]) % MOD;
}
}
}
int main () {
memset (h,-1,sizeof (h));
cin >> n >> m;
while (m--) {
int a,b;
cin >> a >> b;
add (a,b),add (b,a);
}
spfa ();
for (int i = 1;i <= n;i++) cout << cnt[i] << endl;
return 0;
}
边权为1时,SPFA和BFS就等价了,如果边权不一致时,是不能在找最短路的过程中记录最短路的条数的,因为SPFA本身不具有拓扑序,是一种迭代的思想
错误的,只有边权为 1 才能这么干,因为边权为 1 BFS 和 SPFA 等价,但凡不是就是错的,SPFA 并不满足拓扑序,大家不要学习,与其这么写还不如用 BFS,或者你想学习通法那就去写 SPFA 求出最短路再建图再 topsort
那是有环的情况吧?其他情况都能得到正确答案啊。
并不是,你理解错误,假设边权存在负数的时候也不会得到正确答案,回想一下 SPFA 的过程,遍历的过程并不成一个拓扑序,会往回更新,那么你统计答案的时候,如果说存在 的情况 我们先更新了后面的点,但是前面还没有更新好,那么我们是否可以把到前一个点的最短路的条数赋给最后一个点呢?显然不行,我们不能知道前面一个点到最后一个点是累加还是赋值
跟图是否有环没有关系,SPFA 的遍历顺序本来就不是拓扑序
那就是有负权回路啊,此时都没有最短路啊
即使它遍历的顺序不是拓扑序,只要无环就是按拓扑序遍历的(应该把)
有没有一种可能 SPFA 做没有负权回路的图的时候本身就不是拓扑序呢
SPFA 负权的时候不就是还会往后走吗,那能是拓扑序吗??,能不能目光不要放在这题通过了,假如这题有负权呢?
负权->负权回路
负权回路跟负权能是一个玩意?
自己点开视频看一看 y 总怎么讲的好吧,我既然有底气质疑你,就说明你确实有问题,我也是想纠正你的错误认知,以及不要误人子弟,请认真对待一下这个问题好吗
那你的意思是代码错了,还是讲解错了
如有错误,我一定会改正。
我的意思是,有负权无负环并不影响它有最短路,也就不影响他有最短路的数量
不过这道题目确实不用 SPFA
我就是想说不能直接用 SPFA 啊,需要额外处理这件事啊,但是你没有额外处理过了是因为这题权为 1,凑巧而已,我一开始不就在说这个问题吗
我的意思是,有负权无负环并不影响它有最短路,也就不影响他有最短路的数量。不是我又没有说负权就没有最短路数量了,我说的是你的统计方式有问题好吗
哦,我有空改一下
噢我知道你说的 负权->负权回路 是想说无向图的情况下,我想说的是,如果在有向图中有负权,那么直接 SPFA 是做不了的,没有说清楚,我的错
无向图正权也是错误的:
hack 数据
明白了,就是SPFA本身不支持求最短路径数量,它重复更新会有问题是吗?
建议看一下 y 总的视频,文字不如视频更容易理解
好的
附上%%%%
楼主的写法只是把bfs的写法加了一个st数组,这个标记数组在这题并没有什么用处,我觉得不能算是bfs写法吧
这是 SPFA 算法,不是我自创的。