题意:
给定一个有重边有自环的无向图,n个点(2 <= n <= 100000), m条边(1 <= m <= 200000), 每条边有一个权值, 求从第一个点到n的最少步数, 如果最少步数相同有多条路径, 那么输出权值字典序最小的一条。
分析:
用BFS解决最短路问题, 可以先从终点BFS, 求出每个点到终点的最短距离。 那么最少步数就是起点的最短距离, 最短路径就是从起点每次向最短距离比自己少1的顶点移动(如果有多个则可以随便走), 这样就可以保证走的是最短路径, 如果一开始我们是从起点BFS, 那么这样则不能保证走的是通往终点的最短路径。然后我们就可以从起点出发, 循环最短距离次, 每次选择字典序最少的走, 如果有多个字典序相同则选择多个, 直到走完最短距离, 就可以得出答案。 注意两次BFS都需要添加标记, 不然重边很可能就会导致TLE。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxm = 1e7; 4 const int maxn = 1e6 + 7; 5 const int inf = 1e9; 6 struct Node{ 7 int v,col,next; 8 Node():v(0),col(0),next(0){} 9 }; 10 struct ele{ 11 int v; 12 int dist; 13 ele(int v, int dist):v(v),dist(dist){} 14 }; 15 16 Node edge[maxn]; 17 int G[maxn], d[maxn]; 18 bool vis[maxn]; 19 int n, m, cnt; 20 21 void build(){ 22 memset(G,-1,sizeof(G)); 23 cnt = 0; 24 for(int i = 0; i < m; i++){ 25 int u, v, col; 26 scanf("%d %d %d", &u, &v, &col); 27 if(u == v) continue; 28 edge[cnt].v = v; 29 edge[cnt].col = col; 30 edge[cnt].next = G[u]; 31 G[u] = cnt++; 32 edge[cnt].v = u; 33 edge[cnt].col = col; 34 edge[cnt].next = G[v]; 35 G[v] = cnt++; 36 } 37 } 38 39 void revbfs(){ 40 fill(d,d+maxn, inf); 41 memset(vis,0,sizeof(vis)); 42 queue<ele> q; 43 q.push(ele(n,0)); 44 d[n] = 0; 45 vis[n] = 1; 46 while(!q.empty()){ 47 ele u = q.front(); q.pop(); 48 d[u.v] = u.dist; 49 for(int i = G[u.v]; i != -1; i = edge[i].next){ 50 int v = edge[i].v; 51 if(d[v] < u.dist + 1 || vis[v]){ 52 continue; 53 } 54 q.push(ele(v,u.dist+1)); 55 vis[v] = 1; 56 } 57 } 58 } 59 void bfs(){ 60 vector<int> path; 61 memset(vis,0,sizeof(vis)); 62 vis[1] = 1; 63 vector<int> next; 64 next.push_back(1); 65 for(int i = 0; i < d[1]; i++){//the essential minimum step 66 int min_col = inf; 67 for(int j = 0; j < next.size(); j++){ 68 int u = next[j]; 69 for(int k = G[u]; k != -1; k = edge[k].next){ 70 int v = edge[k].v; 71 if(d[u] == d[v] + 1) 72 min_col = min(min_col,edge[k].col); 73 } 74 } 75 //find out the minimum color 76 path.push_back(min_col); 77 78 vector<int> next2; 79 for(int j = 0; j < next.size(); j++){ 80 int u = next[j]; 81 for(int k = G[u]; k != -1; k= edge[k].next){ 82 int v = edge[k].v; 83 if(d[u] == d[v] + 1 && !vis[v] && edge[k].col == min_col){ 84 vis[v] = 1; 85 next2.push_back(v); 86 } 87 } 88 } 89 next = next2; 90 } 91 92 93 printf("%d %d",(int)path.size(),path[0]); 94 for(int i = 1; i < path.size(); i++){ 95 printf(" %d",path[i]); 96 } 97 puts(""); 98 } 99 int main(){ 100 freopen("1.txt","r",stdin); 101 while(~scanf("%d %d", &n, &m)){ 102 build(); 103 revbfs();//反向bfs求出终点到每个点的最短距离 104 bfs(); 105 } 106 printf("%.3f",(double)clock()/CLOCKS_PER_SEC); 107 return 0; 108 }