题目描述
给出一个NNN个顶点MMM条边的无向无权图,顶点编号为1−N1-N1−N。问从顶点111开始,到其他每个点的最短路有几条。
输入格式
第一行包含222个正整数N,MN,MN,M,为图的顶点数与边数。
接下来MMM行,每行222个正整数x,yx,yx,y,表示有一条顶点xxx连向顶点yyy的边,请注意可能有自环与重边。
输出格式
共NNN行,每行一个非负整数,第iii行输出从顶点111到顶点iii有多少条不同的最短路,由于答案有可能会很大,你只需要输出ans mod 100003 ans \bmod 100003ansmod100003后的结果即可。如果无法到达顶点iii则输出000。
输入输出样例
输入 #1 复制
5 7 1 2 1 3 2 4 3 4 2 3 4 5 4 5
输出 #1 复制
1 1 1 2 4
说明/提示
111到555的最短路有444条,分别为222条1−2−4−51-2-4-51−2−4−5和222条1−3−4−51-3-4-51−3−4−5(由于4−54-54−5的边有222条)。
对于20%20\%20%的数据,N≤100N ≤ 100N≤100;
对于60%60\%60%的数据,N≤1000N ≤ 1000N≤1000;
对于100%100\%100%的数据,N<=1000000,M<=2000000N<=1000000,M<=2000000N<=1000000,M<=2000000。
思路
- 利用广搜的特性,第一个访问到的点的距离必为最短距离,固定最短距离,用于后面对比不同路径到达该点时比较距离长度。
- 当前路径个数 = 所有源的路径个数的和
实现代码
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1e6 + 5;
const int mod = 1e5 + 3;
const int inf = 0x3f3f3f3f;
int dis[maxn], cal[maxn], vis[maxn];
vector<int> edge[maxn];
void bfs() {
memset(dis, inf, sizeof(dis));
memset(cal, 0, sizeof(cal));
memset(vis, 0, sizeof(vis));
vis[1] = 1, cal[1] = 1;
queue<int> q; q.push(1);
while (q.size()) {
int now = q.front(); q.pop();
for (int i = 0; i < edge[now].size(); i++) {
int to = edge[now][i];
// 固定最短路距离
if (!vis[to]) dis[to] = dis[now] + 1, vis[to] = 1, q.push(to);
// 若从 now 点到 to 的距离等于最短路距离,则把now点的所有路径加到 to 中
if (dis[to] == dis[now] + 1) cal[to] = (cal[to] + cal[now]) % mod;
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n, m, u, v;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> u >> v;
edge[u].push_back(v);
edge[v].push_back(u);
}
bfs();
for (int i = 1; i <= n; i++) {
if (cal[i] == inf) cout << 0 << endl;
else cout << cal[i] % mod << endl;
}
return 0;
}