题目

给n个点m条边(2 ≤ n ≤ 100000,1 ≤ m ≤ 200000)的无向图,每条边上都涂有一种颜色。求从结点1到结点n的一条路径,使得经过的边数尽量的少,在此前提下,经过边的颜色序列的字典序最小。一对结点间可能有多条边,一条边可能连接两个相同的结点。输入保证结点1可以到达结点n。颜色为1~109的整数。

解题思路

方法是从终点开始倒着BFS,得到每个结点 i 到终点的最短距离d[i]。然后直接从起点开始走,但是每次到达一个新结点时要保证d值恰好减少1,直到到达终点,这样得到的一定是一条最短路。

有了上述结论,可以这样解决:直接从起点开始按照上述规则走,如果有多种走法,选择颜色字典序最小的走;如果有多条边的颜色字典序都最小,则记录所有这些边的终点,走下一步时要考虑从所有这些点出发的边。这实际上是又做了一次BFS,因此时间复杂度仍为 O(m)。

代码实现

  1. #include<stdio.h>
  2. #include<iostream>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<vector>
  6. #include<queue>
  7. using namespace std;
  8.  
  9. const int maxn = + ;
  10. vector<int>G[maxn];
  11. vector<int>C[maxn];
  12. int n, m,vis[maxn], d[maxn], ans[maxn]; //d保存距离,ans保存最小距离
  13.  
  14. void init()
  15. {
  16. int x, y;
  17. int tmp;
  18. memset(vis, , sizeof(vis));
  19. memset(d, , sizeof(d));
  20. memset(ans, , sizeof(ans));
  21. for (int i = ; i <=n; i++) G[i].clear();
  22. for (int i = ; i <= n; i++) C[i].clear();
  23. for (int i = ; i < m; i++)
  24. {
  25. cin >> x >> y;
  26. G[x].push_back(y); G[y].push_back(x);
  27. cin >> tmp;
  28. C[x].push_back(tmp); C[y].push_back(tmp);
  29. }
  30. }
  31.  
  32. void bfs1() //进行距离的遍历,得到d数组
  33. {
  34. memset(d, -, sizeof(d));
  35. queue<int>q;
  36. d[n] = ;
  37. q.push(n);
  38. while (!q.empty())
  39. {
  40. int u = q.front(); q.pop();
  41. int sz = G[u].size();
  42. for (int i = ; i < sz; i++)
  43. {
  44. int v = G[u][i];
  45. if (d[v] == -)
  46. {
  47. d[v] = d[u] + ;
  48. q.push(v);
  49. }
  50. }
  51. }
  52. return;
  53. }
  54.  
  55. void bfs2() //对颜色进行排序,并保存颜色
  56. {
  57. memset(vis, , sizeof(vis));
  58. queue<int>q;
  59. q.push();
  60. while (!q.empty())
  61. {
  62. int u = q.front(); q.pop();
  63. if (d[u] == ) return;
  64. int sz = G[u].size();
  65. int mm = -;
  66. for (int i = ; i < sz; i++)
  67. {
  68. int v = G[u][i];
  69. if (d[v] == d[u] - )
  70. {
  71. if (mm == -) mm = C[u][i];
  72. else mm = min(mm, C[u][i]);
  73. }
  74. }
  75. int t = d[] - d[u];
  76. if (ans[t] == ) ans[t] = mm;
  77. else ans[t] = min(ans[t], mm);
  78.  
  79. for (int i = ; i < sz; i++) //将所有同时满足条件的节点加入队列,并同时进行bfs
  80. {
  81. int v = G[u][i];
  82. if (vis[v] == false && d[v] == d[u] - && C[u][i] == mm)
  83. {
  84. q.push(v);
  85. vis[v] = true;
  86. }
  87. }
  88. }
  89. return;
  90. }
  91.  
  92. int main()
  93. {
  94. while (scanf("%d%d",&n,&m) == )
  95. {
  96. init();
  97. bfs1();
  98. bfs2();
  99. printf("%d\n", d[]);
  100. for (int i = ; i < d[]; i++)
  101. {
  102. if (i) printf(" ");
  103. printf("%d", ans[i]);
  104. }
  105. printf("\n");
  106. }
  107. return ;
  108. }

参考链接:https://blog.csdn.net/cfarmerreally/article/details/52128440

理想路径——双向BFS的更多相关文章

  1. UVA 1599, POJ 3092 Ideal Path 理想路径 (逆向BFS跑层次图)

    大体思路是从终点反向做一次BFS得到一个层次图,然后从起点开始依次向更小的层跑,跑的时候选则字典序最小的,由于可能有多个满足条件的点,所以要把这层满足条件的点保存起来,在跑下一层.跑完一层就会得到这层 ...

  2. POJ 3170 Knights of Ni (暴力,双向BFS)

    题意:一个人要从2先走到4再走到3,计算最少路径. 析:其实这个题很水的,就是要注意,在没有到4之前是不能经过3的,一点要注意.其他的就比较简单了,就是一个双向BFS,先从2搜到4,再从3到搜到4, ...

  3. BFS、双向BFS和A*

    BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个 ...

  4. UVA1601-The Morning after Halloween(双向BFS)

    Problem UVA1601-The Morning after Halloween Accept: 289 Submit: 3136 Time Limit: 12000 mSec  Problem ...

  5. Eight (HDU - 1043|POJ - 1077)(A* | 双向bfs+康拓展开)

    The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...

  6. HDU 1043 Eight(双向BFS+康托展开)

    http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用 ...

  7. BFS:HDU2612-Find a way(双向BFS)

    Find a way Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. POJ1077 Eight —— 双向BFS

    主页面:http://www.cnblogs.com/DOLFAMINGO/p/7538588.html (代码一直在精简完善……) 代码一:两个BFS, 两段代码: 用step控制“你一步, 我一步 ...

  9. Nightmare Ⅱ(双向BFS)

    Problem Description Last night, little erriyue had a horrible nightmare. He dreamed that he and his ...

随机推荐

  1. E20180512-hm

    travesal n. 横越,横断物,(横向)往返移动;

  2. test markdown style

    code // Forward declaration of isBadVersion API. bool isBadVersion(int version); class Solution { pu ...

  3. POJ2406【KMP-next数组】

    关于next的解释原文:点点点 //#include <bits/stdc++.h> #include<cstdio> #include<string.h> #in ...

  4. 51nod1393

    思路:一个位num0-num1值=某位num0-num1值相等就代表这段区间内01数字相等,然后还要判断当前位置num0==num1这个情况 #include <bits/stdc++.h> ...

  5. perl C/C++ 扩展(三)

    第三讲扩展库使用c++实现,在调用函数后,返回对象变量,perl 能正确使用所有对象成员 使用h2xs 命令生成初始文件 h2xs -A -n three_test 登录目录 cd three_tes ...

  6. seq(2018.10.24)

    一道\(dp\)题... 期望\(40\)分解法 预处理:离散化,然后让连续一段值相同的元素合并为一个元素. 正式\(DP\): 显然有个最差策略为每个元素处都切一次,则切的次数为元素的个数\(-1\ ...

  7. C# 对DataTable中按条件进行筛选和更新。

    当我们频繁的对数据库进行操作时,可能造成CPU使用率过高,这时我们可以先将数据表读取到DataTable,然后在必要的时候再更新到数据库中. 以下是DataTable中对数据的选择和更新操作.采用Da ...

  8. 去掉UItalbeview横线

    一.去掉UItalbeview中所有横线 //    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 二.自定义U ...

  9. Day2课后作业:购物车简单版

    PRODUCT_LIST = [ ['iphone7',6500], ['macbook',12000], ['pythonbook',66], ['bike',999], ['coffee',31] ...

  10. 用python将多个文档合成一个

    可以参考下以下网址(读写文件):https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/ ...