Loading

P1144 题解

洛谷 P1144 最短路计数

题目传送门

题意

给出一个 \(n\) 个顶点 \(m\) 条边的无向无权图,顶点编号为 \(1 \sim n\)。 问从顶点 \(1\) 开始,到其他每个点的最短路有几条。

\(1 \le n \le 10 ^ 6, 1 \le m \le 2 \times 10 ^ 6\)

思路

首先,这个题目时非常明显是搜索的。

然后,看见 \(n\)\(10 ^ 6\) 这么大,又是最短路,肯定不能考虑深搜,那就只能考虑广搜了。

最短路应该都会搜,那么,问题就在,怎么记录最短路呢?

首先,我们先写一遍最短路。

void Record(int u, int x, int step) {
  if (d[x]) {  // 如果被遍历过
    return ;
  }
  d[x] = step, que.push(x);  // 记录答案,加入队列
}

void bfs() {
  for (Record(0, 1, 1); !que.empty(); ) {
    int u = que.front();  // 取出队头
    que.pop();
    for (int i = 0; i < f[u].size(); i++) {
      Record(u, f[u][i], d[u] + 1);  // 转移
    }
  }
}

现在的确找到最短路了,但是,要怎么求数量呢?

可以发现,1 -> 2 -> 41 -> 3 -> 4 的长度都是 \(3\) ,都是最短路,所以在统计答案的时候又加上了 \(1\)\(3\) 的路径数量。

那么,就可以这样来分类:

  1. 如果当前点没有被遍历过:直接记录答案,将当前元素加入队列。

  2. 如果当前点被遍历过:设当前点是从点 \(x\) 转移而来的,就加上 \(ans_x\)

所以,代码就很简单了。

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int n, m, a, b;
int d[N], ans[N];

queue<int> que;
vector<int> f[N];

void Record(int u, int x, int step) {
  if (d[x]) {
    if (step == d[x]) {  // 如果当前是最短路
      ans[x] = (ans[u] + ans[x]) % 100003;  // 统计答案
    }
    return ;
  }
  d[x] = step, ans[x] = ans[u];  //记录答案
  que.push(x);  // 放入队列
}

void bfs() {
  ans[0] = 1;  // 将虚拟点赋值答案
  for (Record(0, 1, 1); !que.empty(); ) {
    int u = que.front();  // 取出队头
    que.pop();
    for (int i = 0; i < f[u].size(); i++) {  //转移
      Record(u, f[u][i], d[u] + 1);
    }
  }
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> m;
  while (m--) {
    cin >> a >> b;
    // 建图
    f[a].push_back(b);
    f[b].push_back(a);
  }
  bfs();
  for (int i = 1; i <= n; i++) {
    cout << ans[i] % 100003 << '\n';
  }
  return 0;
}
posted @ 2023-03-02 22:48  chengning0909  阅读(13)  评论(0编辑  收藏  举报