思路
- 要求一个图的最短路径数,首先如果我们用dp的思想cnt[i]表示这个点的最短路径数,一旦这个点被x更新了,那么cnt[i]=cnt[t],如果两个路径距离相等就cnt[i]+=cnt[t],但是这样做要有个前提,必须顺序是拓扑的,因为cnt更新时候要保证dist[t]就是t这个点的最短路径,这题保证了没有权为0的环,所以这里最短路径树就是一个拓扑图,就可以直接用bfs或者dijkstra来做,因为bfs和dijkstra的更新顺序就是拓扑的,但是spfa不行,因为spfa更新的时候不能保证那个值就是最小值,而bfs入队一次出队一次,dijkstra只出队一次,这两个都可以满足拓扑的要求,所以这题可以直接用用这两个求一边最短路,中间更新cnt即可
- spfa也可一个求,而且有优点,如果一个图里面有负权,那么bfs和dijkstra就不能用了,但是spfa可以,步骤就是先求一边最短路,然后枚举一个点的每一条边,如果满足dist[i]=dist[t]+w[i]的话,就证明t点过来的路径就是i点的最小路径中的一个,所以cnt[i]+=cnt[t]即可
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 100010, M = 400010, mod = 100003;
int h[N];int ne[M];int e[M];int idx;
int dist[N];int cnt[N];
void add(int a,int b,int c){
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
bool st[N];
int n,m;
void bfs(){
memset(dist,0x3f,sizeof dist);
queue<int> q;
dist[1]=0;
q.push(1);
cnt[1]=1;
while(q.size()){
int t=q.front();
q.pop();
if(st[t])continue;
st[t]=true;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(dist[t]+1<dist[j]){
dist[j]=dist[t]+1;
cnt[j]=cnt[t];
q.push(j);
}
else if(dist[t]+1==dist[j]){
cnt[j]=(cnt[j]+cnt[t])%mod;
}
}
}
}
int main(){
memset(h,-1,sizeof h);
cin >> n >> m;
while(m--){
int a;int b;
cin >> a >> b;
add(a,b,1);
add(b,a,1);
}
bfs();
for(int i=1;i<=n;i++){
cout << cnt[i] << "\n";
}
}