题目大意:n个点,m条无向边,边权值为正,有k条特殊无向边,起止点和权值已知,求从起点到终点的边权值最小的路径,特殊边最多只能走一条。
题目分析:用两次dijkstra求出起点到任何一个点的最小权值,任何一个点到终点的最小权值,枚举每一条特殊边,取最小的权值。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<vector> # include<cstring> # include<algorithm> using namespace std; const int INF=1<<29; struct Node { int u,t; Node(int _u,int _t):u(_u),t(_t){} bool operator < (const Node &a) const { return t>a.t; } }; struct Edge { int w,to,nxt; }; Edge e[4005]; int n,head[505],d[2][505],path[2][505],vis[505],cnt; void add(int u,int v,int w) { e[cnt].to=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt++; } void dijkstra(int S,int id) { for(int i=0;i<=n;++i) path[id][i]=i; fill(d[id],d[id]+n+1,INF); d[id][S]=0; priority_queue<Node>q; memset(vis,0,sizeof(vis)); q.push(Node(S,0)); while(!q.empty()) { Node u=q.top(); q.pop(); if(vis[u.u]) continue; vis[u.u]=1; for(int i=head[u.u];i!=-1;i=e[i].nxt){ if(d[id][e[i].to]>u.t+e[i].w){ d[id][e[i].to]=u.t+e[i].w; path[id][e[i].to]=u.u; if(!vis[e[i].to]) q.push(Node(e[i].to,d[id][e[i].to])); } } } } void print(int u) { if(path[0][u]==u) printf("%d",u); else{ print(path[0][u]); printf(" %d",u); } } int main() { int S,E,m,a,b,c,flag=0; while(~scanf("%d%d%d",&n,&S,&E)) { if(flag) printf(" "); flag=1; cnt=0; memset(head,-1,sizeof(head)); scanf("%d",&m); while(m--) { scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } dijkstra(S,0); dijkstra(E,1); int ans=d[0][E],ansa=-1,ansb; scanf("%d",&m); for(int i=1;i<=m;++i) { scanf("%d%d%d",&a,&b,&c); if(d[0][a]<INF&&d[1][b]<INF&&d[0][a]+c+d[1][b]<ans){ ans=d[0][a]+d[1][b]+c; ansa=a,ansb=b; } if(d[0][b]<INF&&d[1][a]<INF&&d[0][b]+c+d[1][a]<ans){ ans=d[0][b]+d[1][a]+c; ansa=b,ansb=a; } } if(ansa==-1){ print(E); printf(" "); }else{ print(ansa); while(path[1][ansb]!=ansb){ printf(" %d",ansb); ansb=path[1][ansb]; } printf(" %d ",ansb); } if(ansa==-1) printf("Ticket Not Used "); else printf("%d ",ansa); printf("%d ",ans); } return 0; }