这道题看了下很多人都是把每一层拆成两个点然后建图做的。
我的思路很直接,也不用建图,直接在更新每个点时更新他相邻的边和相邻的层,当然前提是每个点只更新一次,每个层也只更新一次,这样才能确保时间复杂度。
这里我用了两个邻接表,一个是邻接边,一个是邻接层,最后用优先队列优化下。
下面是代码
#include<stdio.h> #include<string.h> #include<queue> #include<vector> using namespace std; const int M=2*111111; int fir[M],u[M],v[M],w[M],nxt[M],e;//边的邻接 int n,m,c; int lfir[M],lu[M],lnxt[M],le;//层的邻接 int lay[M];//表示每个点所在的层 int dis[M],vis[M];//dis表示与起点距离,vis标记边是否访问过 int lvis[M];//表示层是否访问过 struct cmp { bool operator()(int a,int b) { return dis[a]>dis[b]; } }; priority_queue<int,vector<int>,cmp>Q; void linsert(int la,int num)//插入层 { lu[le]=num; lnxt[le]=lfir[la]; lfir[la]=le++; } void insert(int a,int b,int c)//插入边 { u[e]=a;v[e]=b;w[e]=c; nxt[e]=fir[a]; fir[a]=e++; } const int inf=2000000000; int bfs() { int i,j,k,tm; for(i=1;i<=n;i++)dis[i]=(i==1?0:inf); memset(vis,0,sizeof(vis)); memset(lvis,0,sizeof(lvis)); while(!Q.empty())Q.pop(); Q.push(1); while(!Q.empty()) { int p=Q.top();Q.pop(); if(p==n)break; if(vis[p])continue; vis[p]=1; for(k=fir[p];k!=-1;k=nxt[k])if(dis[ v[k] ]>dis[p]+w[k]){//更新边 dis[ v[k] ]=dis[p]+w[k]; Q.push(v[k]); } if(lvis[lay[p]])continue; lvis[lay[p]]=1; tm=lay[p]-1; for(k=lfir[tm];k!=-1;k=lnxt[k])if(dis[ lu[k] ]>dis[p]+c){//更新上一层 dis[ lu[k] ]=dis[p]+c; Q.push(lu[k]); } tm=lay[p]+1; for(k=lfir[tm];k!=-1;k=lnxt[k])if(dis[ lu[k] ]>dis[p]+c){//更新下一层 dis[ lu[k] ]=dis[p]+c; Q.push(lu[k]); } } if(dis[n]==inf)return -1; return dis[n]; } int main() { int t,i,j,k,cas=1; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&c); le=0; memset(lfir,-1,sizeof(lfir)); for(i=1;i<=n;i++){ scanf("%d",&lay[i]); linsert(lay[i],i); } int a,b,c; e=0; memset(fir,-1,sizeof(fir)); for(i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); insert(a,b,c); insert(b,a,c); } int ans=bfs(); printf("Case #%d: %d\n",cas++,ans); } return 0; }