最短路计数
题目描述
给出一个 N N N 个顶点 M M M 条边的无向无权图,顶点编号为 1 1 1 ~ N N N。
问从顶点 1 1 1 开始,到其他每个点的最短路有几条。
输入格式
第一行包含 2 2 2 个正整数 N , M N, M N,M,为图的顶点数与边数。
接下来 M M M 行,每行两个正整数 x , y x, y x,y,表示有一条顶点 x x x 连向顶点 y y y 的边,请注意可能有自环与重边。
输出格式
输出 N N N 行,每行一个非负整数,第 i i i 行输出从顶点 1 1 1 到顶点 i i i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出 m o d mod mod 100003 100003 100003 后的结果即可。如果无法到达顶点 i i i 则输出 0 0 0。
样例
样例输入
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5样例输出
1
1
1
2
4样例解释
1 1 1 到 5 5 5 的最短路有 4 4 4 条,分别为 2 2 2 条 1 − > 2 − > 4 − > 5 1->2->4->5 1−>2−>4−>5 和 2 2 2 条 1 − > 3 − > 4 − > 5 1->3->4->5 1−>3−>4−>5 (由于 4 − > 5 4->5 4−>5 的边有2条) 。
数据范围与提示
对于 20 20 20% 的数据, N ≤ 100 N ≤ 100 N≤100;
对于 60 60 60% 的数据, N ≤ 1000 N ≤ 1000 N≤1000;
对于 100 100 100% 的数据, N ≤ 100000 , 0 ≤ M ≤ 200000 N ≤ 100000, 0 ≤ M ≤ 200000 N≤100000,0≤M≤200000。
这道题是道最短路,只是需要求的不再是最短路径了,而是求从
1
1
1 到每个点有多少条最短路径。
我们可以用
d
i
s
[
i
]
dis[i]
dis[i] 来储存
1
1
1 ~
i
i
i 的最短路,用
p
r
e
[
i
]
[
j
]
pre[i][j]
pre[i][j] 来储存第
i
i
i 个点的第
j
j
j 个前缀。
用 Dijkstra 来求出最短路,在求最短路的时候就可以把前缀求出来了。
最后把每个点的前缀的答案全部加起来就是这个点的答案了。(可能有点绕,看代码可能容易理解些~)
正解代码如下:
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MOD = 100003;
const int MAXN = 1e5 + 5;
int N, M, S, T;
struct edge
{
int V, W;
edge(){}
edge(int v, int w) { V = v, W = w; }
friend bool operator < (edge a, edge b) { return a.W > b.W; }
};
vector<int> G[MAXN], pre[MAXN];
int dis[MAXN], dp[MAXN];
bool vis[MAXN];
void addEdge(int s, int t)
{
G[s].push_back(t);
G[t].push_back(s);
}
void Dijkstra(int s)
{
memset(dis, 0x3f, sizeof(dis));
priority_queue<edge> q;
q.push(edge(s, 0));
dis[s] = 0;
while (!q.empty())
{
int u = q.top().V;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
int num = G[u].size();
for (int i = 0; i < num; i++)
{
int v = G[u][i], w = 1;
if (dis[u] + w == dis[v])
pre[v].push_back(u);
if (dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
pre[v].clear(); // 重新储存前缀
pre[v].push_back(u);
q.push(edge(v, dis[v]));
}
}
}
}
int dfs(int n)
{
if (dp[n]) return dp[n] % MOD;
int num = pre[n].size();
if (num == 0) return dp[n] = 1;
for (int i = 0; i < num; i++)
dp[n] += (dfs(pre[n][i])) % MOD;
return dp[n] % MOD;
}
int main()
{
scanf("%d %d", &N, &M);
for (int i = 1; i <= M; i++)
{
int X, Y;
scanf("%d %d", &X, &Y);
addEdge(X, Y);
}
Dijkstra(1);
for (int i = 1; i <= N; i++)
{
if (dis[i] == INF) printf("0\n");
else printf("%d\n", dfs(i));
}
return 0;
}