该题需要有拓扑性质的bfs和dijkstra来做,
同时,控制spfa的结点顺序,也可以实现拓扑树。
思路来源于:y总
bfs
#include <iostream>
#include <cstring>
#include <algorithm>
// #include <qu
using namespace std;
const int N = 1e5 + 10, M = 4e5 + 10, mod = 100003;
int h[N],e[M],w[M],ne[M],idx;
int dis[N],cnt[N];
int n,m;
int q[N];
void add(int a, int b){
e[idx] = b, ne[idx] = h[a],h[a] = idx++;
}
void bfs(){
memset(dis,0x3f,sizeof(dis));
dis[1] = 0;
cnt[1] = 1;
int hh = 0, tt = 0;
q[tt++] = 1;
while(hh < tt){
int t = q[hh++];
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dis[j] > dis[t] + 1){
dis[j] = dis[t] + 1;
cnt[j] = cnt[t];
q[tt++] = j;
}
else if(dis[j] == dis[t] + 1){
cnt[j] = (cnt[t] + cnt[j]) % mod;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
bfs();
for(int i = 1; i <= n; i++){
printf("%d\n",cnt[i]);
}
return 0;
}
spfa
需反复理解,spfa函数中的
dis[j] == dis[t] + 1这段代码
不太理解重边,它(上述代码)是如何实现计算的。
实现:链式前向星、队列(类似bfs)
以及因边权为1,所以最短路为上一个结点加1.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int n,m;
const int N = 1e6 + 10, M = 2e6 + 10, mod = 1e5 + 3;
int h[N],e[N],ne[N],cnt[N],idx;
int dis[N];
bool st[N];
int ans;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void spfa(){
dis[1] = 0;
st[1] = true;
queue<int> q;
q.push(1);
cnt[1] = 1;//1到1的路径为1,从样例可以看出。
while(q.size()){
int t = q.front();
q.pop();
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
// cout <<"i = " << i << "j = " << j << endl;
if(!st[j]){
st[j] = 1;
dis[j] = dis[t] + 1;
q.push(j);
}
if(dis[j] == dis[t] + 1){//不太理解,重边是如何算的
cnt[j] = (cnt[t] + cnt[j]) % mod;
}
}
}
for(int i = 1; i <= n; i++){
cout << cnt[i] << endl;
}
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
spfa();
return 0;
}
本文探讨了如何使用BFS(广度优先搜索)和SPFA(最短路径优先搜索)算法解决穿越隧道的问题,特别强调了控制SPFA中节点顺序的重要性,并介绍了在实际场景中如何通过链式前向星和队列实现拓扑树。着重解析了重边在SPFA中的处理方式,适合对图论算法有深入理解的读者。

627

被折叠的 条评论
为什么被折叠?



