洛谷P1144《最短路计数》

最短路“板子”

题目描述

给出一个 N 个顶点 M 条边的无向无权图,顶点编号为 1-N 。问从顶点 1 开始,到其他每个点的最短路有几条。

输入输出格式

输入格式

第一行包含 2 个正整数 N,M ,为图的顶点数与边数。

接下来 M 行,每行 2 个正整数 x,y ,表示有一条顶点 x 连向顶点 y 的边,请注意可能有自环与重边。

输出格式

N 行,每行一个非负整数,第 i 行输出从顶点 1 到顶点 i 有多少条不同的最短路,由于答案有可能会很大,你只需要输出 ans \bmod 100003 后的结果即可。如果无法到达顶点 i 则输出 0

输入输出样例

输入样例

1
2
3
4
5
6
7
8
5 7
1 2
1 3
2 4
3 4
2 3
4 5
4 5

输出样例

1
2
3
4
5
1
1
1
2
4

说明

1 5 的最短路有 4 条,分别为 2 1-2-4-5 2 1-3-4-5 (由于 4−5 的边有 2 条)。

对于 20\% 的数据, N ≤ 100

对于 60\% 的数据, N ≤ 1000

对于 100\% 的数据, N<=1000000,M<=2000000

解题思路

稍微改一下最短路板子即可

具体就是用 ans[i] 数组记录一下到i点的最短路个数,在更新路径长度的时候判一下两条路径长度的关系即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const int HA = 100006;

/* ... */

for (int e = head[now]; e; e = edge[e].next) {
int to = edge[e].now;
if (dis[to] > dis[now] + edge[e].weight) {
// 两条路径长度不等,更新答案
dis[to] = dis[now] + edge[e].weight;
ans[to] = ans[now];
q.push(NewNode(dis[to], to));
} else if (dis[to] == dis[now] + edge[e].weight) {
// 两条路径长度相等,将答案相加
ans[to] += ans[now];
ans[to] %= HA;
}
}

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* -- Basic Headers -- */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>

/* -- STL Iterators -- */
#include <vector>
#include <string>
#include <stack>
#include <queue>

/* -- External Headers -- */
#include <map>
#include <cmath>

/* -- Defined Functions -- */
#define For(a,x,y) for (int a = x; a <= y; ++a)
#define Forw(a,x,y) for (int a = x; a < y; ++a)
#define Bak(a,y,x) for (int a = y; a >= x; --a)

namespace FastIO {

inline int getint() {
int s = 0, x = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') x = -1;
ch = getchar();
}
while (isdigit(ch)) {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * x;
}
inline void __basic_putint(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x >= 10) __basic_putint(x / 10);
putchar(x % 10 + '0');
}

inline void putint(int x, char external) {
__basic_putint(x);
putchar(external);
}
}


namespace Solution {
const int HA = 100003;

struct Graph {
static const int MAXN = 1000000 + 10;
static const int MAXM = 2000000 + 10;

struct Node {
int nweight, now;

Node() { nweight = now = 0; }

bool operator < (const Node &that) const {
return nweight > that.nweight;
}
};

struct Edge {
int now, weight, next;
} edge[MAXM * 2];

int head[MAXN], dis[MAXN], ans[MAXN], cnt;

inline void addEdge(int prev, int next, int weight, bool isR = true) {
if (isR) { addEdge(next, prev, weight, false); }
edge[++cnt].now = next;
edge[cnt].weight = weight;
edge[cnt].next = head[prev];
head[prev] = cnt;
}

inline Node NewNode(int nowWeight, int now) {
Node tmp;
tmp.nweight = nowWeight;
tmp.now = now;
return tmp;
}

inline void SPFA() {
memset(dis, 0x7f, sizeof(dis));
memset(ans, 0, sizeof ans);
std::priority_queue<Node> q;
q.push(NewNode(0, 1));
dis[1] = 0;
ans[1] = 1;
while (!q.empty()) {
Node NowNode = q.top();
q.pop();
int now = NowNode.now;
for (int e = head[now]; e; e = edge[e].next) {
int to = edge[e].now;
if (dis[to] > dis[now] + edge[e].weight) {
dis[to] = dis[now] + edge[e].weight;
ans[to] = ans[now];
q.push(NewNode(dis[to], to));
} else if (dis[to] == dis[now] + edge[e].weight) {
ans[to] += ans[now];
ans[to] %= HA;
}
}
}
}
} g1;

int n, m;
}

signed main() {
#define HANDWER_FILE
#ifndef HANDWER_FILE
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
using namespace Solution;
using FastIO::getint;
n = getint();
m = getint();
For (i, 1, m) {
int prev = getint();
int next = getint();
g1.addEdge(prev, next, 1);
}
g1.SPFA();
For (i, 1, n) {
FastIO::putint(g1.ans[i], '\n');
}
return 0;
}