分层图最短路 && 洛谷 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
几乎完全相同,改一改起点终点参数等即可。
(三倍经验太快乐)

posted @ 2021-09-28 15:38  尹昱钦  阅读(47)  评论(0编辑  收藏  举报