https://vjudge.net/problem/UVA-1599

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

分析:

  1. 从题目中我们可以看出,题目中的无向图是可以出现自环和重边的,自环我们可以在输入的时候检查并排除,但是重边我们需要保留,并从中选择颜色最小的边。
  2. 题目的数据量很大,不可能采用邻接矩阵存储图,因此应采用邻接表,且邻接表便于进行bfs
  3. 路径的颜色不代表路径的权重,本题中路径是无权的

思路:

从终点开始倒着bfs一次,得到每个点到终点的距离,然后从起点开始,按照每次距离减1的方法寻找接下来的点的编号。按照颜色最小的走,如果有多个颜色最小,则都拉入队列中,将最小的颜色记录在res数组中。

其中,index=d[0]-d[u]就得到了当前u节点对应的距离,也就是步骤数。

细节:

  1. 已经进入队列的节点不能重复入队,否则复杂度太高,会tle(重复入队的复杂度至少是O(n^2),在n=100000的情况下直接tle)
  2. 第一次bfs和第二次bfs的终止时机不同,第一次找到起点就终止,第二次则是从队列中取出节点时才能终止,为的是遍历完所有导向终点且路径长度一致的边,只有这样才能结果正确
  3. d数组记录每个节点到终点n的距离,不能用0进行初始化,而终点处的初始化必须是0
  4. d数组不能不初始化,否则对于多输入题目,前面的输入可能影响后面的输出
    1. 1 #include <iostream>
    2. 2 #include <algorithm>
    3. 3 #include <string>
    4. 4 #include <sstream>
    5. 5 #include <set>
    6. 6 #include <vector>
    7. 7 #include <stack>
    8. 8 #include <map>
    9. 9 #include <queue>
    10. 10 #include <deque>
    11. 11 #include <cstdlib>
    12. 12 #include <cstdio>
    13. 13 #include <cstring>
    14. 14 #include <cmath>
    15. 15 #include <ctime>
    16. 16 #include <functional>
    17. 17 using namespace std;
    18. 18
    19. 19 #define maxn 100000
    20. 20 #define inf 0x7fffffff
    21. 21
    22. 22 typedef struct ver
    23. 23 {
    24. 24 int num, color; //边的另一端的结点编号 和 颜色
    25. 25 ver(int n, int c) : num(n), color(c) {}
    26. 26 } Ver;
    27. 27
    28. 28 int n, m, a, b, c;
    29. 29 int d[maxn], res[maxn]; //d记录每个点到终点的最短距离 res记录最短路的颜色
    30. 30 bool vis[maxn], inqueue[maxn]; //vis每个结点是否被访问过 inqueue标记结点是否加入了队列,防止重复加入
    31. 31 vector<Ver> edge[maxn]; //邻接表记录图
    32. 32
    33. 33 void bfs(int start, int end)
    34. 34 {
    35. 35 memset(inqueue, 0, n);
    36. 36 memset(vis, 0, n);
    37. 37 int u, v, c;
    38. 38 queue<int> q;
    39. 39 q.push(start);
    40. 40 if (start == 0) //用于正向BFS
    41. 41 {
    42. 42 memset(res, 0, sizeof(int) * n);
    43. 43 while (!q.empty())
    44. 44 {
    45. 45 u = q.front();
    46. 46 q.pop();
    47. 47 vis[u] = 1;
    48. 48 if (u == n - 1)
    49. 49 return;
    50. 50 int minc = inf, len = edge[u].size();
    51. 51 for (int i = 0; i < len; i++)
    52. 52 if (!vis[v = edge[u][i].num] && d[u] - 1 == d[v])
    53. 53 minc = min(edge[u][i].color, minc); //获取所有路径中最小的颜色
    54. 54 for (int i = 0; i < len; i++)
    55. 55 if (!vis[v = edge[u][i].num] && d[u] - 1 == d[v] && edge[u][i].color == minc && !inqueue[v])
    56. 56 q.push(v), inqueue[v] = 1; //若有多组颜色相同且未入队,则将其入队
    57. 57 int index = d[0] - d[u]; //获得当前步数对应的下标
    58. 58 if (res[index] == 0)
    59. 59 res[index] = minc;
    60. 60 else
    61. 61 res[index] = min(res[index], minc); //获取最小颜色
    62. 62 }
    63. 63 }
    64. 64 else
    65. 65 while (!q.empty()) //用于反向DFS 构建层次图,找最短路
    66. 66 {
    67. 67 u = q.front();
    68. 68 q.pop();
    69. 69 vis[u] = 1;
    70. 70 for (int i = 0, len = edge[u].size(); i < len; i++)
    71. 71 if (!vis[v = edge[u][i].num] && !inqueue[v])
    72. 72 {
    73. 73 d[v] = d[u] + 1; //一定是头一次入队,这通过inqueue保证
    74. 74 if (v == 0)
    75. 75 return; //找到起点退出
    76. 76 q.push(v); //如果不是起点,就把这个点入队
    77. 77 inqueue[v] = 1; //入队标记
    78. 78 }
    79. 79 }
    80. 80 }
    81. 81
    82. 82 int main()
    83. 83 {
    84. 84 while (scanf("%d%d", &n, &m) == 2)
    85. 85 {
    86. 86 for (int i = 0; i < n; i++)
    87. 87 edge[i].clear();
    88. 88 memset(d, -1, sizeof(int) * n);
    89. 89 d[n - 1] = 0; //初始化的细节
    90. 90 while (m--)
    91. 91 {
    92. 92 scanf("%d%d%d", &a, &b, &c);
    93. 93 if (a != b) //排除自环
    94. 94 {
    95. 95 edge[a - 1].push_back(ver(b - 1, c));
    96. 96 edge[b - 1].push_back(ver(a - 1, c));
    97. 97 }
    98. 98 }
    99. 99 bfs(n - 1, 0); //先反向BFS
    100. 100 bfs(0, n - 1); //再正向BFS
    101. 101 printf("%d\n%d", d[0], res[0]);
    102. 102 for (int i = 1; i < d[0]; i++)
    103. 103 printf(" %d", res[i]);
    104. 104 printf("\n");
    105. 105 }
    106. 106 return 0;
    107. 107 }

UVA 1599 Ideal Path(双向bfs+字典序+非简单图的最短路+队列判重)的更多相关文章

  1. UVa1599 Ideal Path(双向bfs+字典序+非简单图的最短路+队列判重)

    题目大意: 对于一个n个房间m条路径的迷宫(Labyrinth)(2<=n<=100000, 1<=m<=200000),每条路径上都涂有颜色,颜色取值范围为1<=c&l ...

  2. Uva 1599 Ideal Path - 双向BFS

    题目连接和描述以后再补 这题思路很简单但还真没少折腾,前后修改提交了七八次才AC...(也说明自己有多菜了).. 注意问题: 1.看清楚原题的输入输出要求,刚了书上的中文题目直接开撸,以为输入输出都是 ...

  3. UVa 1599 Ideal Path【BFS】

    题意:给出n个点,m条边,每条边上涂有一个颜色,求从节点1到节点n的最短路径,如果最短路径有多条,要求经过的边上的颜色的字典序最小 紫书的思路:第一次从终点bfs,求出各个节点到终点的最短距离, 第二 ...

  4. uva 1599 ideal path(好题)——yhx

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABGYAAAODCAYAAAD+ZwdMAAAgAElEQVR4nOy9L8/0ypH/Pa8givGiyC

  5. UVA 1599 Ideal Path(bfs1+bfs2,双向bfs)

    给一个n个点m条边(<=n<=,<=m<=)的无向图,每条边上都涂有一种颜色.求从结点1到结点n的一条路径,使得经过的边数尽量少,在此前提下,经过边的颜色序列的字典序最小.一对 ...

  6. 【每日一题】 UVA - 1599 Ideal Path 字典序最短路

    题解:给一个1e5个点2e5条边,每个边有一个值,让你输出一条从1到n边的路径使得:条数最短的前提下字典序最小. 题解:bfs一次找最短路(因为权值都是1,不用dijkstra),再bfs一次存一下路 ...

  7. UVa 1599 Ideal Path (两次BFS)

    题意:给出n个点,m条边的无向图,每条边有一种颜色,求从结点1到结点n颜色字典序最小的最短路径. 析:首先这是一个最短路径问题,应该是BFS,因为要保证是路径最短,还要考虑字典序,感觉挺麻烦的,并不好 ...

  8. UVA 1599 Ideal Path (HDU 3760)

    两次bfs: 第一次bfs逆向搜索,得到每个点到终点的最短距离,找出最短路:第二次bfs根据最短距离可以选择满足条件的最短路. 注意!碰到这种很大数据量的题目一定要记得用scanf,printf 输入 ...

  9. UVA 1599 Ideal Path

    题意: 给出n和m,n代表有n个城市.接下来m行,分别给出a,b,c.代表a与b之间有一条颜色为c的道路.求最少走几条道路才能从1走到n.输出要走的道路数和颜色.保证颜色的字典序最小. 分析: bfs ...

随机推荐

  1. Notes about WindowPadX

    WindowPadX乃一Autohotkey脚本,具有强大的单/多显示器窗口排布能力且易于配置.有了它,那些Pro版收费的.需要安装的DisplayFusion, MultiMon TaskBar, ...

  2. 更好地使用Atom支持基于Jupyter的Python开发

    有关于使用Atom进行Python开发的网上资料比较少,最近发现使用Atom结合Hydrogen插件进行Python开发,尤其是数据挖掘相关的工作,整体体验要好于Vscode,Vscode虽然说也有连 ...

  3. java批量下载文件为zip包

    批量下载文件为zip包的工具类 package com.meeno.trainsys.util; import javax.servlet.http.HttpServletRequest; impor ...

  4. RHEL 7 “There are no enabled repos” 的解决方法

    RHEL 7 "There are no enabled repos"  的解决方法 [root@system1 Desktop]# yum install squidLoaded ...

  5. Java-线程池专题 (美团)

    实现多线程的三种方式,继承Thread,实现Runnable 和 实现 Executor接口 ,具体参考:Java 多线程 三种实现方式 去美团,问到了什么是线程池,如何使用,为什么要用,以下做个总结 ...

  6. 【转】Mysql中事务ACID实现原理

    转自:https://www.cnblogs.com/rjzheng/p/10841031.html 作者:孤独烟 引言 照例,我们先来一个场景~ 面试官:"知道事务的四大特性么?" ...

  7. 使用volatile的条件

    使用volatile的值不能依赖于它之前的值: volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果. ...

  8. JDBC基础篇(MYSQL)——使用CallabeStatement调用存储过程

    注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package day04_callable; import java.sql.CallableStatement; import ...

  9. kettle 乱码问题处理方案

    一.同下图加上 "-Dfile.encoding=UTF-8" ,两都都加没有试过,可先加一处,如果没有处理到问题,再加另外一处

  10. CentOS7部署SSH服务

    1 ssh服务部署 输入命令 yum list | grep ssh 查看可安装的软件包,选择openssh-service.x86_64 输入下面命令进行安装openssh服务 yum instal ...