题意:
给出一个图(图中可能含平行边,可能含环),每条边有一个颜色标号。在从节点1到节点n的最短路的前提下,找到一条字典序最小的路径。
分析:
首先从节点n到节点1倒着BFS一次,算出每个节点到节点n个最短距离di
然后从节点1开始再一次BFS,在寻找下一个节点时,必须满足下一个节点v满足对于当前节点u,有du = dv + 1,这样才能保证在最短路上。
在这个条件下还要满足v的颜色编号是最小的。因为可能有多个颜色相同的最小编号,所以这些节点都要保留下来。
图的表示方式:这里如果再用往常的邻接表发现不适用了,所以G[u]中保存的与u邻接的edges中边的编号。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 100000 + 10; 9 const int INF = 1000000000 + 10; 10 11 struct Edge 12 { 13 int u, v, c; 14 Edge(int u=0, int v=0, int c=0):u(u), v(v), c(c) {} 15 }; 16 17 vector<Edge> edges; 18 vector<int> G[maxn]; 19 20 void AddEdge(int u, int v, int c) 21 { 22 edges.push_back(Edge(u, v, c)); 23 int index = edges.size() - 1; 24 G[u].push_back(index); 25 } 26 27 int n, d[maxn]; 28 bool vis[maxn]; 29 vector<int> ans; 30 31 void rev_bfs() 32 { 33 memset(vis, 0, sizeof(vis)); 34 queue<int> q; 35 q.push(n-1); 36 vis[n-1] = true; 37 d[n-1] = 0; 38 39 while(!q.empty()) 40 { 41 int u = q.front(); q.pop(); 42 for(int i = 0; i < G[u].size(); ++i) 43 { 44 int e = G[u][i]; 45 int v = edges[e].v; 46 if(!vis[v]) 47 { 48 vis[v] = true; 49 d[v] = d[u] + 1; 50 q.push(v); 51 } 52 } 53 } 54 } 55 56 void bfs() 57 { 58 memset(vis, 0, sizeof(vis)); 59 vis[0] = true; 60 ans.clear(); 61 62 vector<int> next; 63 next.push_back(0); 64 for(int i = 0; i < d[0]; ++i) 65 { 66 int min_color = INF; 67 for(int j = 0; j < next.size(); ++j) 68 { 69 int u = next[j]; 70 for(int k = 0; k < G[u].size(); ++k) 71 { 72 int e = G[u][k]; 73 int v = edges[e].v; 74 if(d[u] == d[v] + 1) 75 min_color = min(min_color, edges[e].c); 76 } 77 } 78 ans.push_back(min_color); 79 80 vector<int> next2; 81 for(int j = 0; j < next.size(); ++j) 82 { 83 int u = next[j]; 84 for(int k = 0; k < G[u].size(); ++k) 85 { 86 int e = G[u][k]; 87 int v = edges[e].v; 88 if(!vis[v] && d[u] == d[v] + 1 && edges[e].c == min_color) 89 { 90 vis[v] = true; 91 next2.push_back(v); 92 } 93 } 94 } 95 next = next2; 96 } 97 98 printf("%d %d", d[0], ans[0]); 99 for(int i = 1; i < ans.size(); ++i) printf(" %d", ans[i]); 100 puts(""); 101 } 102 103 int main() 104 { 105 //freopen("in.txt", "r", stdin); 106 int m, u, v, c; 107 while(scanf("%d%d", &n, &m) == 2) 108 { 109 edges.clear(); 110 for(int i = 0; i < n; ++i) G[i].clear(); 111 while(m--) 112 { 113 scanf("%d%d%d", &u, &v, &c); 114 if(u == v) continue; //最短路中一定不含环 115 AddEdge(u-1, v-1, c); 116 AddEdge(v-1, u-1, c); 117 } 118 119 rev_bfs(); 120 bfs(); 121 } 122 123 return 0; 124 }