New labyrinth attraction is open in New Lostland amusement park. The labyrinth consists of n rooms connected by m passages. Each passage is colored into some color ci . Visitors of the labyrinth are dropped from the helicopter to the room number 1 and their goal is to get to the labyrinth exit located in the room number n. Labyrinth owners are planning to run a contest tomorrow. Several runners will be dropped to the room number 1. They will run to the room number n writing down colors of passages as they run through them. The contestant with the shortest sequence of colors is the winner of the contest. If there are several contestants with the same sequence length, the one with the ideal path is the winner. The path is the ideal path if its color sequence is the lexicographically smallest among shortest paths. Andrew is preparing for the contest. He took a helicopter tour above New Lostland and made a picture of the labyrinth. Your task is to help him find the ideal path from the room number 1 to the room number n that would allow him to win the contest. Note: A sequence (a1, a2, . . . , ak) is lexicographically smaller than a sequence (b1, b2, . . . , bk) if there exists i such that ai < bi , and aj = bj for all j < i.
Input
The input file contains several test cases, each of them as described below. The first line of the input file contains integers n and m — the number of rooms and passages, respectively (2 ≤ n ≤ 100000, 1 ≤ m ≤ 200000). The following m lines describe passages, each passage is described with three integer numbers: ai , bi , and ci — the numbers of rooms it connects and its color (1 ≤ ai , bi ≤ n, 1 ≤ ci ≤ 109 ). Each passage can be passed in either direction. Two rooms can be connected with more than one passage, there can be a passage from a room to itself. It is guaranteed that it is possible to reach the room number n from the room number 1.
Output
For each test case, the output must follow the description below. The first line of the output file must contain k — the length of the shortest path from the room number 1 to the room number n. The second line must contain k numbers — the colors of passages in the order they must be passed in the ideal path.
Sample Input
4 6
1 2 1
1 3 2
3 4 3
2 3 1
2 4 4
3 1 1
Sample Output
2 1 3
题解:
有两种方法:
第一种:先用BFS处理出没一点到1号店的最短距离,然后再BFS寻找字典序最小的;
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn=1e5+10; int n,m,i,j,k,u,v,w; int first[maxn],pre[maxn],q[maxn],dis[maxn],vis[maxn]; struct edge{ int x,y,c; int nxt; } edge[maxn<<2]; void Init() { memset(first,0,sizeof(first)); memset(pre,0,sizeof(pre)); memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); } int main() { ios::sync_with_stdio(false); cin.tie(0); while(cin>>n>>m) { Init(); for(i=1,j=0;j<m;j++,i+=2) { cin>>u>>v>>w; edge[i].x=u; edge[i].y=v; edge[i].c=w; edge[i+1].x=v; edge[i+1].y=u; edge[i+1].c=w; edge[i].nxt=first[u]; first[u]=i; edge[i+1].nxt=first[v]; first[v]=i+1; } q[0]=n; int l=0,r=1; pre[1]=pre[0]=0; dis[n]=0; vis[n]=1; while(l<r) { int x=q[l++]; for(j=first[x];j;j=edge[j].nxt) { int V=edge[j].y,W=edge[j].c; if(vis[V]) { if(dis[V]==dis[x]+1) { int e1=pre[V],e2=j; while(e1!=e2 && edge[e1].c==edge[e2].c) e1=pre[edge[e1].x],e2=pre[edge[e2].x]; if(edge[e1].c>edge[e2].c) pre[V]=j; } } else { vis[V]=1; pre[V]=j; dis[V]=dis[x]+1; q[r++]=V; } } } cout<<dis[1]<<endl; for(int e=pre[1],i=0;i<dis[1];i++) { if(i) cout<<' '; cout<<edge[e].c; e=pre[edge[e].x]; } cout<<endl; } return 0; }
我主要说第二种:一个BFS就可一解决问题:
我们可以倒着处理;用邻接表存边的信息;pre[i]表示i前面的那条边,dis[i]表示i到n号点的最短距离;vis[i]代表i点是否访问过;
我对于每一个点的子节点,判断其是否被访问过,如果没被访问过,则dis[v]=dis[u]+1; pre[v]=v和u相连的边的编号,标记为访问过,然后该点入队;
如被访问过:则如果当前路径长度与已有的v点路径长度相等,则从该点分别往两条路上回溯pre数组,直到其父亲节点相同,或者出现了一条边的颜
色与另一条边的颜色不同,则将其pre[v]更新为颜色小的那条边即可,直到访问到1号节点;
参考代码为:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn=1e5+10; int n,m,k,u,v,w,tot; int first[maxn],pre[maxn],q[maxn],dis[maxn],vis[maxn]; struct edge{ int U,V,W,nxt; } edge[maxn<<2]; void Init() { memset(first,-1,sizeof first); memset(pre,0,sizeof pre); memset(dis,0,sizeof dis); memset(vis,0,sizeof vis); tot=1; } void addedge(int u,int v,int w) { edge[tot].U=u; edge[tot].V=v; edge[tot].W=w; edge[tot].nxt=first[u]; first[u]=tot++; } void search() { q[0]=n; int l=0,r=1; dis[n]=0; vis[n]=1; while(l<r) { int u=q[l++]; for(int j=first[u];j;j=edge[j].nxt) { int V=edge[j].V,W=edge[j].W; if(vis[V]) { if(dis[V]==dis[u]+1) { int x=pre[V],y=j; while(x!=y && edge[x].W==edge[y].W) x=pre[edge[x].U],y=pre[edge[y].U]; if(edge[x].W>edge[y].W) pre[V]=j; } } else { vis[V]=1; pre[V]=j; dis[V]=dis[u]+1; q[r++]=V; } } } } int main() { ios::sync_with_stdio(false); cin.tie(0); while(cin>>n>>m) { Init(); for(int i=0;i<m;i++) { cin>>u>>v>>w; addedge(u,v,w); addedge(v,u,w); } search(); cout<<dis[1]<<endl; for(int e=pre[1],i=0;i<dis[1];i++) { if(i) cout<<' '; cout<<edge[e].W; e=pre[edge[e].U]; } cout<<endl; } return 0; }