关于最短路算法的拓扑序列
最短路计数问题
题目
思路
我们考虑依赖方式(动态规划的思想):
1. 先求出**全局最小值**是多少
2. 再分别求出每个子集中**等于全局最小值**的元素个数
如果存在环形依赖关系的话,这样并不能求出最终的数量。
我们举例环形依赖问题:
小王欠小张100元,小张欠小刘100元,小刘欠小王100元,显然着三个人互不相欠,但是我们按照动态规划的思想,小王->小张->小刘 得出结论每个人互相欠100元,因为动规是将重叠子问题并为图论中的一个节点,在跑一个DAG的推导,如果存在环形依赖关系,\(f\)可能需要多次被推导。
最短路树(拓扑图)满足\(dist[v] = dist[u] + w(u \rightarrow v)\). 即该节点被其前去节点所更新。
如果该图存在权重等于\(0\)的环,显然该图存在无穷多个最短路序列,如果该权重\(<0\)则不存在最短路。
对\(BFS或Dijkstra\) 显然都满足每一次出队的点都是满足拓扑序的,对于\(SPFA\)算法每次出队的时候由于该点的最短距离并不能被确定,我们并不能求出最短路的拓扑序。但是如果存在负权的话我们并不能使用Dijkstra,这时候需要使用SPFA算法先把最短路径求出来,然后再求最短路径树。
Code
#include <iostream>
#include <cstring>
using i64 = long long;
const int N = 1e5 + 10, M = 4e5 + 10, mod = 1e5 + 3;
int n, m;
int h[N], ne[M], e[M], idx;
int q[N], hh = 0, tt = -1;
int dist[N], cnt[N];
void add(int a, int b) {
ne[idx] = h[a], h[a] = idx, e[idx ++] = b;
}
void bfs() {
memset(dist, 0x3f, sizeof dist);
q[++ tt] = 1;
dist[1] = 0;
cnt[1] = 1;
while (hh <= tt) {
int t = q[hh]; hh ++;
for (int i = h[t]; ~i; i = ne[i]) {
int v = e[i];
if (dist[v] > dist[t] + 1) {
dist[v] = dist[t] + 1;
cnt[v] = cnt[t];
q[++ tt] = v;
} else if (dist[v] == dist[t] + 1) {
cnt[v] = (cnt[v] + cnt[t]) % mod;
}
}
}
}
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i ++) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
bfs();
for (int i = 1; i <= n; i ++) {
printf("%d\n", cnt[i]);
}
}