【图论算法】分层图最短路径
分层图,很简单
举个例题https://www.luogu.com.cn/problem/P4822
所谓分层图,可能会有k种情况来改变图的边权状况等,这时可以建k层图
对于每一层中,按照第一层即初始状况去建图
然后在相邻两层中对于可能会发生变化的边的两点,或者是按照意义需要额外连接的两点之间,再建一次边
对于数据范围,开k倍大小,然后每一层即为u+(k-1)*n
当然,具体情况自己得手推确定。
那么对于例题,就是建了k层图后,对于终点n,每一层都要去比较,以得到答案
#include<cstdio> #include<iostream> #include<queue> #include<cctype> #include<cstring> using namespace std; inline int read(){ int s=0;bool flag=true;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')flag=false;ch=getchar();} while(isdigit(ch)){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return flag?s:-s; } #define inf 0x3f3f3f const int N=50+5; const int M=2000+10; int n,m,k,cnt,ans=inf; int head[N*N],dis[N*N]; bool inq[N*N]; struct edge{int v,w,next;}e[(N*M)<<1]; inline void addedge(int u,int v,int w){ e[++cnt]=(edge){v,w,head[u]};head[u]=cnt; } inline void spfa(){ queue<int> q; memset(dis,inf,sizeof(dis)); dis[1]=0;inq[1]=true; q.push(1); while(!q.empty()){ int u=q.front();q.pop(); inq[u]=false; for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(dis[v]>dis[u]+e[i].w){ dis[v]=dis[u]+e[i].w; if(!inq[v]){ inq[v]=true; q.push(v); } } } } } signed main(){ n=read(),m=read(),k=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(),w=read(); for(int j=0;j<=k;j++){ addedge(u+j*n,v+j*n,w); addedge(v+j*n,u+j*n,w); if(j!=k){ addedge(u+j*n,v+(j+1)*n,w/2); addedge(v+j*n,u+(j+1)*n,w/2); } } } spfa(); for(int i=0;i<=k;i++) ans=min(ans,dis[n+i*n]); cout<<ans<<endl; return 0; }
再放一个题https://www.luogu.com.cn/problem/P4568
(这个题很气人,有两个原因,一是因为这个题卡了spfa,另一个原因是打题的那天,我们班一个大佬gxm给题作者反应这个题太简单,然后紫题减1,蓝题加1,淦!)
其实意思与打法都差不多,但是这个题莫名其妙有个hack点,需要把每层图的终点相连
//分层图+dij #include<cstdio> #include<iostream> #include<queue> #include<cctype> #include<cstring> using namespace std; inline int read(){ int s=0;bool flag=true;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')flag=false;ch=getchar();} while(isdigit(ch)){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return flag?s:-s; } #define inf 0x3f3f3f const int N=2e5+10; const int M=5e5+10; int n,m,k,s,t,cnt,ans=inf; int head[N<<5],dis[N<<5]; bool vis[N<<5]; struct edge{int v,w,next;}e[M<<5]; inline void addedge(int u,int v,int w){ e[++cnt]=(edge){v,w,head[u]};head[u]=cnt; } typedef pair<int,int> pii; inline void dijkstra(){ memset(dis,inf,sizeof(dis)); dis[s]=0; memset(vis,0,sizeof(vis)); priority_queue<pii,vector<pii>,greater<pii> >q; q.push(make_pair(0,s)); while(!q.empty()){ int u=q.top().second; q.pop(); if(vis[u]) continue; vis[u]=true; for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(dis[v]>dis[u]+e[i].w){ dis[v]=dis[u]+e[i].w; q.push(make_pair(dis[v],v)); } } } } signed main(){ n=read(),m=read(),k=read(); s=read(),t=read(); for(int i=1;i<=m;i++){ int u=read(),v=read(),w=read(); for(int j=0;j<=k;j++){ addedge(u+j*n,v+j*n,w); addedge(v+j*n,u+j*n,w); if(j<k){ addedge(u+j*n,v+(j+1)*n,0); addedge(v+j*n,u+(j+1)*n,0); } } } for(int i=1;i<=k;i++) addedge(t+(i-1)*n,t+i*n,0); dijkstra(); cout<<dis[t+k*n]<<endl; return 0; }