CSES 1667 Message Route 题解

Message Route

题目大意

\(n\) 个节点和 m 条无向边,节点编号为 \(1 \sim n\),问节点 \(1\) 和节点 \(n\) 之间是否连通。

  • 如连通,输出最短路径长度和任意一条最短路径中包含的所有点
  • 如不连通,输出IMPOSSIBLE

思路

首先,我们要大致了解一下最短路,利用BFS,我们可以用 O(n + m) 的时间复杂度来求出从 \(1\)\(n\) 的最短路径。

可以用vector去存储每条边,即邻接表

BFS

首先,将初始状态加入到队列当中。

  1. 处理队头,可以转移到许多的点上。
    · 先要弹出队头
    · 如果当前转移到的点没有被遍历过,那么这个点的最短路径肯定是由队头转移而来。由于要记录路径,那么在这里记录一下这个点是由队头转移而来。
    · 如果遍历过了,那么长度肯定不会比当前路径还要短,所以不需要记录。
  2. 如果队列空了,那么其他没有入过队列的节点肯定与节点 \(1\) 是不连通的。结束bfs
  3. 如果队列非空,那么执行操作 \(1\)

最后判断答案,输出答案即可。

路径输出详见代码注释。

Code

点击查看代码
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int N = 1e5 + 10;

int n, m, x, y, vis[N], fa[N], q[N], h, t;
vector<int> v[N];

void record (int x_, int x, int lv) { // 处理当前队头转移到的点
  if (vis[x]) { // 它已经被遍历过
    return ;
  }
  vis[x] = lv;
  q[t++] = x;
  fa[x] = x_; // 记录 bfs 树中当前节点的父亲
}

void bfs () {
  record(1, 1, 1); // 处理初始状态
  while (h < t) {
    int _ = q[h++];
    for (int i = 0; i < v[_].size(); i++) { // 队头能够转移到的点
      record(_, v[_][i], vis[_] + 1);
    }
  }
}

void Print (int x) { // 输出路径处理
  if (x != 1) { // 它不是开始的点
    Print(fa[x]); // 先要去遍历它的父亲
  }
  cout << x << ' '; // 输出当前的点
}

int main(){
  cin >> n >> m;
  for (int i = 1; i <= m; i++) {
    cin >> x >> y;
    v[x].push_back(y);
    v[y].push_back(x); // 无向图
  }
  bfs();
  if (!vis[n]) { // 非连通
    cout << "IMPOSSIBLE";
  } else {
    cout << vis[n] << '\n';
    Print(n);
  }
  return 0;
}

posted @ 2023-02-13 22:53  wnsyou  阅读(120)  评论(0编辑  收藏  举报