题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1808
Time limit: 5000 ms Memory limit: 131072 kB
Bobo 居住在大城市 ICPCCamp。
Input
Output
对于每组数据,输出一个整数表示要求的值。
Sample Input
3 3 1 2 1 1 2 3 2 1 1 3 1 1 3 3 1 2 1 1 2 3 2 1 1 3 1 10 3 2 1 2 1 1 2 3 1 1
Sample Output
1 3 2
题解:
如果只记录到某个节点x的最短路长度d[x],并且记录对应于d[x],是坐哪号线来到节点x的,这样显然是错误的。
原因比如这样的样例:
3 3
1 2 1 2
1 2 3 3
2 3 3 5
可以看出,d[x]要扩展到d[x][c],即这题的状态有两个量决定:到了节点x,最后乘坐的是c号线;
那么,如果我们把节点x用若干条边Edge(u1→x)…Edge(uk→x)来代替,那么我们就相当于把d[x]要扩展到d[x][c]了;
所以我们可以直接把边当成点,对边做最短路(用堆优化dijkstra)。
AC代码:
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<vector> #include<algorithm> #include<queue> using namespace std; typedef long long LL; typedef pair<LL,int> Pair; const LL INF=1e18; const int maxn=1e5+10; const int maxm=2e5+10; //无向边拆成两条有向边 int n,m; struct Edge{ int u,v,c; int next; LL t; }; Edge E[maxm]; int head[maxn],ne; void init() { ne=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int c,LL t) { E[ne].u=u, E[ne].v=v, E[ne].c=c, E[ne].t=t; E[ne].next=head[u]; head[u]=ne++; } LL ans; LL d[maxm]; bool vis[maxm]; void dijkstra(int st) { priority_queue< Pair, vector<Pair>, greater<Pair> > Q; memset(vis,0,sizeof(vis)); for(int i=0;i<ne;i++) d[i]=INF; ans=INF; for(int i=head[st];i!=-1;i=E[i].next) { d[i]=E[i].t; Q.push(Pair(d[i],i)); } while(!Q.empty()) { int x=Q.top().second; Q.pop(); if(vis[x]) continue; vis[x]=1; if(E[x].v==n) ans=min(ans,d[x]); for(int y=head[E[x].v];y!=-1;y=E[y].next) { if(vis[y]) continue; if(d[y]>d[x]+E[y].t+abs(E[y].c-E[x].c)) { d[y]=d[x]+E[y].t+abs(E[y].c-E[x].c); Q.push(Pair(d[y],y)); } } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=1;i<=m;i++) { int u,v,c; LL t; scanf("%d%d%d%lld",&u,&v,&c,&t); addedge(u,v,c,t); addedge(v,u,c,t); } dijkstra(1); printf("%lld\n",ans); } }
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<vector> #include<algorithm> #include<queue> using namespace std; typedef long long LL; typedef pair<LL,int> Pair; const LL INF=1e18; const int maxn=1e5+10; const int maxm=2e5+10; //无向边拆成两条有向边 int n,m; struct Edge{ int u,v,c; LL t; }; vector<Edge> E; vector<int> G[maxn]; void init(int l,int r) { E.clear(); for(int i=l;i<=r;i++) G[i].clear(); } void addedge(int u,int v,int c,LL t) { E.push_back((Edge){u,v,c,t}); G[u].push_back(E.size()-1); } LL ans; LL d[maxm]; bool vis[maxm]; void dijkstra(int st) { priority_queue< Pair, vector<Pair>, greater<Pair> > Q; memset(vis,0,sizeof(vis)); for(int i=0;i<E.size();i++) d[i]=INF; ans=INF; for(int i=0;i<G[st].size();i++) { int x=G[st][i]; d[x]=E[x].t; Q.push(Pair(d[x],x)); } while(!Q.empty()) { int x=Q.top().second; Q.pop(); if(vis[x]) continue; vis[x]=1; if(E[x].v==n) ans=min(ans,d[x]); for(int i=0;i<G[E[x].v].size();i++) { int y=G[E[x].v][i]; if(vis[y]) continue; if(d[y]>d[x]+E[y].t+abs(E[y].c-E[x].c)) { d[y]=d[x]+E[y].t+abs(E[y].c-E[x].c); Q.push(Pair(d[y],y)); } } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(1,n); for(int i=1;i<=m;i++) { int u,v,c; LL t; scanf("%d%d%d%lld",&u,&v,&c,&t); addedge(u,v,c,t); addedge(v,u,c,t); } dijkstra(1); printf("%lld\n",ans); } }
注:两份代码的区别是分别用链式前向星和vector邻接表存图。
原文:https://www.cnblogs.com/dilthey/p/9016699.html