分层图最短路

思想和应用

当遇到一些需要对边权进行操作的题目时,我们可以建立一些分层图,分别对边权进行修改然后再跑最短路等等来解决问题

例题:Luogu P4568

思路

完全是一个裸题,由于\(k\)的范围较少,所以可以建出\(k+1\)个分层图,分别代表将\(0\)条,\(1\)条......\(k\)条边的边权变为\(0\)。然后再跑一遍\(Dijkstra\),总时间复杂度为\(O(k*(mlog_2m))\)

Code

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=10005,M=100005;
int n,m,k,s,t,tot,ans=2147483647;
int head[N*22],edge[M*22],Nxt[M*22],ver[M*22],d[N*22];
bool v[N*22];
priority_queue < pair <int,int> > q;
void add(int x,int y,int z){
	ver[++tot]=y;
	edge[tot]=z;
	Nxt[tot]=head[x];
	head[x]=tot;
}
void dijkstra(int ss){
	for(int i=0;i<=N*20;i++){
		d[i]=2147483647;
	}
	d[ss]=0;
	q.push(make_pair(0,ss));
	while(!q.empty()){
		int x=q.top().second;
		q.pop();
		if(v[x]) continue;
		v[x]=1;
		for(int i=head[x];i;i=Nxt[i]){
			int y=ver[i],z=edge[i];
			if(d[y]>d[x]+z){
				d[y]=d[x]+z;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	scanf("%d%d",&s,&t);
	s++,t++;
	for(int i=1,x,y,z;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		x++,y++;
		add(x,y,z);
		add(y,x,z);
		for(int j=1;j<=k;j++){
			add(x+j*n,y+j*n,z);
			add(y+j*n,x+j*n,z);//每一层上单独建图
			add(x+(j-1)*n,y+j*n,0);
			add(y+(j-1)*n,x+j*n,0);//层与层之间
		}
	}
	dijkstra(s);
	for(int i=0;i<=k;i++){
		ans=min(ans,d[i*n+t]);//每一层的终点都有可能成为最终的答案
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-02-19 15:21  徐明拯  阅读(55)  评论(0编辑  收藏  举报