Problem
考察算法:拓扑排序 + \(DP\) + \(Dijkstra\)。
题目简述
给出一个无向无权图,问从顶点 \(1\) 开始,到其他每个点的最短路有几条。
思路
-
先求出 \(1\) 号点到每个点的最短路 \(d_i\) 。
-
分析每条边 $(x,y) $:
如果
d[x] + 1 == d[y]
:这条边有用。 -
将所有有用的边拓扑排序。
-
处理队列里面的每一个点 \(x\) ,\(dp_[i] = 1\) ,枚举 \(x\) 所有的出边 \(u\) ,\(dp_u += dp_x\)。
-
记住要边加边取余数!
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10, MOD = 100003;
typedef pair<int, int> PII;
struct node {
int from, to, next;
} a[N * 2];
int pre[N], k, in[N], flag[N];
queue<int> q;
int n, m, x, y, d[N], dp[N];
bool f[N];
void add(int x, int y) {
a[++k] = (node) {x, y, pre[x]};
pre[x] = k;
}
void Dijkstra() {
priority_queue<PII, vector<PII>, greater<PII> > q;
memset(d, 0x3f, sizeof(d));
d[1] = 0;
q.push(make_pair(0, 1));
while (!q.empty()) {
PII h = q.top();
q.pop();
int dis = h.first, p = h.second;
if (f[p]) continue;
f[p] = true;
for (int i = pre[p]; i; i = a[i].next) {
int to = a[i].to;
if (d[p] + 1 < d[to]) {
d[to] = d[p] + 1;
q.push(make_pair(d[to], to));
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
Dijkstra();
for (int i = 1; i <= k; i++) {
if (d[a[i].to] - d[a[i].from] == 1) {
flag[i] = 1;
in[a[i].to]++;
}
}
for (int i = 1; i <= n; i++) {
if (!in[i]) {
if (d[i] != 0x3f3f3f3f)
dp[i] = 1;
q.push(i);
}
}
while (!q.empty()) {
int h = q.front();
q.pop();
for (int i = pre[h]; i; i = a[i].next) {
if (!flag[i]) continue;
int to = a[i].to;
dp[to] = (dp[h] + dp[to]) % MOD;
in[to]--;
if (!in[to]) q.push(to);
}
}
for (int i = 1; i <= n; i++) {
printf("%d\n", dp[i]);
}
return 0;
}
标签:pre,int,题解,短路,P1144,pair,dp
From: https://www.cnblogs.com/yhx0322/p/17739709.html