最短路计数
题目描述
给出一个 N N N 个顶点 M M M 条边的无向无权图,顶点编号为 1 ∼ N 1\sim N 1∼N。问从顶点 1 1 1 开始,到其他每个点的最短路有几条。
输入格式
第一行包含 2 2 2 个正整数 N , M N,M N,M,为图的顶点数与边数。
接下来 M M M 行,每行 2 2 2 个正整数 x , y x,y x,y,表示有一条由顶点 x x x 连向顶点 y y y 的边,请注意可能有自环与重边。
输出格式
共 N N N 行,每行一个非负整数,第 i i i 行输出从顶点 1 1 1 到顶点 i i i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出 $ ans \bmod 100003$ 后的结果即可。如果无法到达顶点 i i i 则输出 0 0 0。
样例 #1
样例输入 #1
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5
样例输出 #1
1
1
1
2
4
提示
1 1 1 到 5 5 5 的最短路有 4 4 4 条,分别为 2 2 2 条 1 → 2 → 4 → 5 1\to 2\to 4\to 5 1→2→4→5 和 2 2 2 条 1 → 3 → 4 → 5 1\to 3\to 4\to 5 1→3→4→5(由于 4 → 5 4\to 5 4→5 的边有 2 2 2 条)。
对于
20
%
20\%
20% 的数据,
1
≤
N
≤
100
1\le N \le 100
1≤N≤100;
对于
60
%
60\%
60% 的数据,
1
≤
N
≤
1
0
3
1\le N \le 10^3
1≤N≤103;
对于
100
%
100\%
100% 的数据,
1
≤
N
≤
1
0
6
1\le N\le10^6
1≤N≤106,
1
≤
M
≤
2
×
1
0
6
1\le M\le 2\times 10^6
1≤M≤2×106。
#include<bits/stdc++.h>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
const int MOD = 100003;
const int N = 1000005;
const int M = 2*N;
//因各边权重为1,所以只存放下一条边的索引与指向结点即可
struct E
{
int next;
int to;
}edge[M];
int idx = 0;
//ans来记录每个节点到原点的最小路径的数目
int head[N],dis[N],ans[N];
bool vis[N] = {false};
//每个节点信息包含到原点的距离与当前位置
struct node
{
int dis;
int pos;
bool operator<(const node &x) const{
return dis>x.dis;
}
};
//建立小根堆
priority_queue<node>p;
//前向星建图
void add(int u,int v)
{
idx++;
edge[idx].to = v;
edge[idx].next = head[u];
head[u] = idx;
}
int main(){
//head与dis数组赋初值
memset(head,-1,sizeof(head));
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
//注意为无向图
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++){
dis[i] = 1e9;
}
//x,y范围从1开始,即原点为1,dis为0
dis[1] = 0;
ans[1] = 1;
p.push({0,1});
//注意循环条件
while(p.size())
{
node temp = p.top();
p.pop();
int t = temp.pos;
if(vis[t])
continue;
vis[t] = true;
for(int i=head[t];i!=-1;i=edge[i].next)
{
int j = edge[i].to;
//如果j结点的dis[]为初始值无穷大,更改其dis[]值
//t能到达的路径,j也一定能够到达,所以有ans[j] = ans[t];
//并同时将其压入栈
if(dis[j]>dis[t]+1){
dis[j] = dis[t] + 1;
ans[j] = ans[t];
p.push((node){dis[j],j});
}
//如果j结点的dis[j] == dis[t] + 1
//说明之前已经经其他结点循环至此结点,而且其刚好为当前结点的后一层结点,即加上当前结点的所有路径数目
else if(dis[j] == dis[t] + 1)
{
ans[j] += ans[t];
ans[j] %= MOD;
}
}
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<endl;
}
return 0;
}