zoukankan      html  css  js  c++  java
  • 理想路径——双向BFS

    题目

    给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 = 100000 + 10;
     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, 0, sizeof(vis));
     19     memset(d, 0, sizeof(d));
     20     memset(ans, 0, sizeof(ans));
     21     for (int i = 0; i <=n; i++)  G[i].clear();
     22     for (int i = 0; i <= n; i++)  C[i].clear();
     23     for (int i = 0; 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, -1, sizeof(d));
     35     queue<int>q;
     36     d[n] = 0;
     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 = 0; i < sz; i++)
     43         {
     44             int v = G[u][i];
     45             if (d[v] == -1)
     46             {
     47                 d[v] = d[u] + 1;
     48                 q.push(v);
     49             }
     50         }
     51     }
     52     return;
     53 }
     54 
     55 void bfs2()    //对颜色进行排序,并保存颜色
     56 {
     57     memset(vis, 0, sizeof(vis));
     58     queue<int>q;
     59     q.push(1);
     60     while (!q.empty())
     61     {
     62         int u = q.front(); q.pop();
     63         if (d[u] == 0)  return;
     64         int sz = G[u].size();
     65         int mm = -1;
     66         for (int i = 0; i < sz; i++)    
     67         {
     68             int v = G[u][i];
     69             if (d[v] == d[u] - 1)
     70             {
     71                 if (mm == -1)  mm = C[u][i];
     72                 else  mm = min(mm, C[u][i]);
     73             }
     74         }
     75         int t = d[1] - d[u];
     76         if (ans[t] == 0)  ans[t] = mm;
     77         else  ans[t] = min(ans[t], mm);
     78 
     79         for (int i = 0; i < sz; i++)   //将所有同时满足条件的节点加入队列,并同时进行bfs
     80         {
     81             int v = G[u][i];
     82             if (vis[v] == false && d[v] == d[u] - 1 && 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) == 2)
     95     {
     96         init();
     97         bfs1();
     98         bfs2();
     99         printf("%d
    ", d[1]);
    100         for (int i = 0; i < d[1]; i++)
    101         {
    102             if (i)  printf(" ");
    103             printf("%d", ans[i]);
    104         }
    105         printf("
    ");
    106     }
    107     return 0;
    108 }

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

  • 相关阅读:
    Java uuid生成随机32位
    Java 、C# Excel模板,数据一对多,主从表关系,导入到数据库
    ROS 八叉树地图构建
    操作系统基础信息搜集
    菜鸟的信息安全学习之路
    提权初探
    Windos/Linux 反弹 shell
    初读鸟哥的linux私房菜的收获
    linux中find命令的摘要
    分享一个Flink checkpoint失败的问题和解决办法
  • 原文地址:https://www.cnblogs.com/lfri/p/9726629.html
Copyright © 2011-2022 走看看