最短路好题啊。
题目给定起点和终点,要求最短路和次短路(要求次短路只比最短路大1)的道路数量。
重点在于次短路如何处理是最高效的呢
这就要求对dij算法路径更新的理解了。
我们用一个数组记录最短路,一个数组记录次短路。
每次对当前最短边,先更新最短路,更新不了最短路再更新次短路。
每条边处理两次,这样就可以在2n×n的复杂度内求得最短路和次短路了。
#include<cstdio> #include<cstring> #include<queue> #include<iostream> #define inf 2000000000 using namespace std; #define N 1010 #define M 10010 struct node { int v,w,next; }e[M]; int h,head[N],vis[N][2],d[N][2],cnt[N][2],n,m,st,en; void addedge(int a,int b,int c) { e[h].v=b; e[h].w=c; e[h].next=head[a]; head[a]=h++; } void dij(int s) { int i,j,v,w,k; memset(vis,0,sizeof vis); memset(cnt,0,sizeof cnt); for(i=0;i<=n;i++) d[i][0]=d[i][1]=inf; d[s][0]=0; cnt[s][0]=1; // vis[s][0]=1; //这里的本意就相当于一个点可以走两次 for(i=0;i<n+n;i++) { int flag=-1,p=-1,dis=inf; for(j=1;j<=n;j++) { if(!vis[j][0]&&d[j][0]<dis) { p=j; dis=d[j][0]; flag=0; } else if(!vis[j][1]&&d[j][1]<dis) { p=j; dis=d[j][1]; flag=1; } } if(flag==-1) break; vis[p][flag]=1; for(k=head[p];k!=-1;k=e[k].next) { v=e[k].v; w=e[k].w; if(d[v][0]>dis+w)//找到的路径比原来的最短路更短 则最短路和次短路都更新 { d[v][1]=d[v][0]; d[v][0]=dis+w; cnt[v][1]=cnt[v][0];//更新该长度路径数目 cnt[v][0]=cnt[p][flag]; } else if(d[v][0]==dis+w) { cnt[v][0]+=cnt[p][flag]; } else if(d[v][1]>dis+w) { d[v][1]=dis+w; cnt[v][1]=cnt[p][flag]; } else if(d[v][1]==dis+w) { cnt[v][1]+=cnt[p][flag]; } } } } void init() { memset(head,-1,sizeof head); h=0; } int main() { int t,a,b,c,i; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); while(m--) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); } scanf("%d%d",&st,&en); dij(st); if(d[en][1]==d[en][0]+1) printf("%d\n",cnt[en][0]+cnt[en][1]); else printf("%d\n",cnt[en][0]); } return 0; }
poj3463 Sightseeing --- dij最短路和次短路,布布扣,bubuko.com
时间: 2024-10-10 10:38:40