题目
给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