①Dijsktra(454ms)
dis[i][0]:表示最短路;dis[i][1]:表示次短路;
每个点用数组vis标记,最短路标记为vis[i][0],次短路标记为vis[i][1];
先把源点加入图中,然后对个边进行松弛,总共需要2*n-1次(n-1次更新最短路,n次更新次短路)
初始化dis[src][0]=0;
每次选取到i点的最短距离的点或者次短距离的点进行松弛,优先松弛最短路,最短路如果可以松弛那么次短路也需要松弛,否则选择松弛次短路,具体实现详见代码。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const double eps=1e-3; const int INF=0x3f3f3f3f; const int maxn=5010; int n,m; int vis[maxn][2],dis[maxn][2],head[maxn]; int edgeNum; struct Edge{ int to; int w; int next; }edge[200010]; void addEdge(int u,int v,int w){ edge[edgeNum].to=v; edge[edgeNum].w=w; edge[edgeNum].next=head[u]; head[u]=edgeNum++; } void Init(){ memset(vis,0,sizeof(vis)); memset(dis,INF,sizeof(dis)); memset(head,-1,sizeof(head)); edgeNum=0; } void Dijsktra(int src,int des){ dis[src][0]=0; for(int i=1;i<2*n;i++){ int pos,min=INF,flag=-1; for(int j=1;j<=n;j++){ if(!vis[j][0]&&min>dis[j][0]){ min=dis[pos=j][0]; flag=0; } else if(!vis[j][1]&&min>dis[j][1]){ min=dis[pos=j][1]; flag=1; } } if(flag==-1) break; vis[pos][flag]=1; for(int j=head[pos];j!=-1;j=edge[j].next){ int v=edge[j].to; if(dis[v][0]>min+edge[j].w){ dis[v][1]=dis[v][0]; dis[v][0]=min+edge[j].w; } else if(dis[v][1]>min+edge[j].w){ dis[v][1]=min+edge[j].w; } } } printf("%d\n",dis[des][1]); } int main(){ #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("test.out","w",stdout); #endif while(~scanf("%d%d",&n,&m)){ Init(); int u,v,w; for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&w); addEdge(u,v,w); addEdge(v,u,w); } Dijsktra(1,n); } return 0; }
②A*+SPFA(157ms)
先用spfa或者dijsktra预处理点n到其他所有点的最短距离dis[i] {i=1,2,...,n-1};
然后BFS进行逐层往下搜索。
设计估价函数f=g+h,用优先队列维护,g为到当前点所花的最小费用,h为到点n所需要的最小费用,即dis[i],每次扩展优先选取总费用最小的点。
当所扩展的点为n的次数为2时,即为次短路。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const double eps=1e-3; const int INF=0x3f3f3f3f; const int maxn=5010; int n,m; int vis[maxn],dis[maxn],head[maxn]; int edgeNum; struct Edge{ int to; int w; int next; }edge[200010]; void addEdge(int u,int v,int w){ edge[edgeNum].to=v; edge[edgeNum].w=w; edge[edgeNum].next=head[u]; head[u]=edgeNum++; } void Init(){ memset(vis,0,sizeof(vis)); memset(dis,INF,sizeof(dis)); memset(head,-1,sizeof(head)); edgeNum=0; } void spfa(int src){ queue<int>q; q.push(src); vis[src]=1; dis[src]=0; while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(dis[v]>dis[u]+edge[i].w){ dis[v]=dis[u]+edge[i].w; if(!vis[v]){ vis[v]=1; q.push(v); } } } } } struct node{ int to; int g,h,f; bool operator<(const node &a)const { return f>a.f||(f==a.f&&g>a.g); } }; void Astar(int src,int des){ priority_queue<node>q; int cnt=0; node s,e; s.to=src; s.g=0; s.h=dis[src]; s.f=s.g+s.h; q.push(s); while(!q.empty()){ s=q.top(); q.pop(); if(s.to==des){ cnt++; if(cnt==2){ printf("%d\n",s.g); return ; } } int u=s.to; for(int i=head[u];i!=-1;i=edge[i].next){ e.to=edge[i].to; e.g=s.g+edge[i].w; e.h=dis[edge[i].to]; e.f=e.g+e.h; q.push(e); } } } int main(){ while(~scanf("%d%d",&n,&m)){ Init(); int u,v,w; for(int i=0;i<m;i++){ scanf("%d%d%d",&u,&v,&w); addEdge(u,v,w); addEdge(v,u,w); } spfa(n); Astar(1,n); } return 0; }