分层图最短路 && 洛谷 P4568 [JLOI2011]飞行路线
传送门
什么是分层图
在一个图上,按照某种限制,进行分层,在相邻两层之间按照某种联系进行连边。
如何实现
一般有两种方法:二维数组法和状态压缩法。
二维数组法:a[i][j]表示第i层的节点j。
状态压缩法:a[j*k+i]表示第i层的节点j,其中k表示层数。(相当于把二维坐标压成一维。)
应用
在分层图上求最短路、网络流等。
限制
对空间的要求较大。
一般数据范围较小。
解题思路
这个题算是个板子。
因为可以选择k条边是免费的。
所以可以建k+1层图,每条边在相邻两层之间的权值为0。
建完图后就是一个裸的最短路了。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
using namespace std;
const int maxm=5e6+5;
const int maxn=2e5+5;
int cnt,n,m,k,s,t,dis[maxn],p[maxn];
struct node{
int v,next,w;
}e[maxm];
void insert(int u,int v,int w){
cnt++;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].next=p[u];
p[u]=cnt;
}
void dij(){
set<pair<int,int> > q;
dis[s]=0;
q.insert(make_pair(dis[s],s));
while(!q.empty()){
int u=q.begin()->second;
if(u%n==t){
cout<<dis[u]<<endl;
return;
}
q.erase(q.begin());
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
q.erase(make_pair(dis[v],v));
dis[v]=dis[u]+e[i].w;
q.insert(make_pair(dis[v],v));
}
}
}
}
int main(){
ios::sync_with_stdio(false);
memset(p,-1,sizeof(p));
memset(dis,0x3f,sizeof(dis));
cin>>n>>m>>k>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
insert(u,v,w);
insert(v,u,w);
for(int j=1;j<=k;j++){
insert(n*j+u,n*j+v,w);
insert(n*j+v,n*j+u,w);
insert(n*(j-1)+u,n*j+v,0);
insert(n*(j-1)+v,n*j+u,0);
}
}
for(int i=0;i<n;i++){
for(int j=1;j<=k;j++){
insert(n*(j-1)+i,n*j+i,0);
}
}
dij();
return 0;
}
其他例题
洛谷 P4822 [BJWC2012]冻结
洛谷 P2939 [USACO09FEB]Revamping Trails G
几乎完全相同,改一改起点终点参数等即可。
(三倍经验太快乐)