从CF1941G学习双端队列实现01BFS

Problem - G - Codeforces

1|0思路

一开始写了一个无脑BFS剪枝求最短路,然后顺带更新最小线路数量,被hack了。

应该直接针对问题处理,通过BFS直接求最小线路数量

这题可以转化成对于一个单点,只有两种选择

  • 走与当前颜色相同的点,答案不变
  • 走与当前颜色不同的点,答案加一

这被描述为 01BFS ,得利于他只有两个可能性,所以可以用双端队列来维护单调性:

  • 更优的状态放头:即走相同的颜色
  • 更劣的状态放尾:即走不同的颜色

2|0实现

  • 建图

    • 建图有说法的,首先边数点数可能过大,而题目只保证了 N×M​ 的空间复杂度合理。

      • 需要牺牲时间换空间,用 std::map 来维护边
    • 维护当前点相连的所有颜色以及所有颜色对应的所有边

      std::vector<std::map<int, std::vector<int>>> adj(n);
  • 判重

    • 这里必须定义 [x,color] 两个变量限制的状态来判重才能保证正确性。
  • 01BFS

    std::map<std::pair<int, int>, int> dis; std::deque<std::tuple<int, int, int>> q; int b, e; std::cin >> b >> e; b--, e--; q.emplace_back(0, b, 0); //双端队列BFS,意在满足单调最优,求的是最小的地铁线路数 while(!q.empty()) { auto [d, x, color] = q.front(); q.pop_front(); if (dis.count({x, color})) {//如果访问过该点并颜色下的状态就去重 continue; } dis[{x, color}] = d; //两种选择,如果颜色相同边权就是0,肯定最优,放到队首。否则放到队尾 if (color) {//判断不是起点,走相同颜色的边 q.emplace_front(d, x, 0); for (auto& to : adj[x][color]) { q.emplace_front(d + 0, to, color); } } else {//准备走不同颜色的边,先切换当前颜色,地铁线路数加一 for (auto&[tcolor, _] : adj[x]) { q.emplace_back(d + 1, x, tcolor); } } }

3|0代码

void solve() { #define tests int n, m; std::cin >> n >> m; std::vector<std::map<int, std::vector<int>>> adj(n);//维护当前点相连的所有颜色以及所有颜色对应的所有边 for (int i = 0; i < m; i++) { int u, v, c; std::cin >> u >> v >> c; u--, v--; adj[u][c].push_back(v); adj[v][c].push_back(u); } std::map<std::pair<int, int>, int> dis; std::deque<std::tuple<int, int, int>> q; int b, e; std::cin >> b >> e; b--, e--; q.emplace_back(0, b, 0); //双端队列BFS,意在满足单调最优,求的是最小的地铁线路数 while(!q.empty()) { auto [d, x, color] = q.front(); q.pop_front(); if (dis.count({x, color})) {//如果访问过该点并颜色下的状态就去重 continue; } dis[{x, color}] = d; //两种选择,如果颜色相同边权就是0,肯定最优,放到队首。否则放到队尾 if (color) {//判断不是起点,走相同颜色的边 q.emplace_front(d, x, 0); for (auto& to : adj[x][color]) { q.emplace_front(d + 0, to, color); } } else {//准备走不同颜色的边,先切换当前颜色,地铁线路数加一 for (auto&[tcolor, _] : adj[x]) { q.emplace_back(d + 1, x, tcolor); } } } std::cout << dis[{e, 0}] << '\n'; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/18069350.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示