一句话题意:一个带点权边权的无向图,输出从1号点到n号点的最短路中字典序最小的一条路径
样例输入:
8 9 1 2 3 4 5 6 7 8 1 2 2 2 3 3 3 8 3 1 4 3 4 5 2 5 8 1 1 6 1 6 7 2 7 8 3
样例输出:
6 1 4 5 8
思路:
跑一边spfa(单源最快),更新条件改成(当前路径更短 or (当前路径和原路径相等 and 当前路径字典序更小)),直接开一个pre数组维护当前点的前继就好。
建议自己写队列,实现只要两分钟(因为代码短),而且不会被卡STL(实际上也没什么变态出题人会去卡一个queue),习惯第一。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<vector> 7 #define ll long long 8 using namespace std; 9 struct edge{ 10 int next,to,w; 11 edge(){ 12 to=w=0;next=-1; 13 } 14 }a[400100]; 15 int n,m,first[200100],bk[200100]; 16 ll dis[200100];bool vis[200100]; 17 ll pre[200100]; 18 struct Queue{ 19 int q[300100],head,tail; 20 Queue(int k){ 21 head=100000;tail=100001;memset(q,0,sizeof(q)); 22 q[head]=k; 23 } 24 void push(int k){ 25 if(dis[k]>dis[q[head]]) q[tail++]=k; 26 else q[--head]=k; 27 } 28 void pop(){ 29 q[head++]=0; 30 } 31 int top(){ 32 return q[head]; 33 } 34 bool empty(){ 35 return (head==tail); 36 } 37 }; 38 void spfa(){ 39 Queue q(n); 40 vis[n]=1;dis[n]=0;pre[n]=n; 41 int u,v,w,i; 42 while(!q.empty()){ 43 u=q.top();q.pop();vis[u]=0; 44 for(i=first[u];~i;i=a[i].next){ 45 v=a[i].to;w=a[i].w; 46 if(dis[v]>dis[u]+w||(dis[v]==dis[u]+w&&bk[pre[v]]>=bk[u])){ 47 dis[v]=dis[u]+w; 48 pre[v]=u; 49 if(!vis[v]){ 50 vis[v]=1;q.push(v); 51 } 52 } 53 } 54 } 55 } 56 int main(){ 57 scanf("%d%d",&n,&m); 58 for(int i=1;i<=n;i++){ 59 first[i]=-1;dis[i]=0x3f3f3f3f3f3f3f; 60 scanf("%d",&bk[i]); 61 } 62 int t1,t2,t3; 63 for(int i=1;i<=m;i++){ 64 scanf("%d%d%d",&t1,&t2,&t3); 65 a[i].to=t1;a[i].next=first[t2];a[i].w=t3;first[t2]=i; 66 } 67 spfa(); 68 printf("%lld %d ",dis[1],bk[1]); 69 int i=1; 70 while(i!=n){ 71 printf("%d ",bk[pre[i]]);i=pre[i]; 72 } 73 }