suxxsfe

一言(ヒトコト)

P4568 [JLOI2011]飞行路线(分层图)

分层图板子题

题目描述

Alice 和 Bob 现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在\(n\)城市设有业务,设这些城市分别标记为 \(0\)\(n-1\),一共有 \(m\) 种航线,每种航线连接两个城市,并且航线有一定的价格。
Alice 和 Bob 现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多 \(k\) 种航线上搭乘飞机。那么 Alice 和 Bob 这次出行最少花费多少?

输入格式

数据的第一行有三个整数,\(n,m,k\),分别表示城市数,航线数和免费乘坐次数。
第二行有两个整数,\(s,t\),分别表示他们出行的起点城市编号和终点城市编号。
接下来有 \(m\) 行,每行三个整数,\(a,b,c\),表示存在一种航线,能从城市 \(a\) 到达城市 \(b\),或从城市 \(b\) 到达城市 \(a\),价格为 \(c\)

输出格式

输出一行一个整数,为最少花费。


建立 \((k+1)n\) 个点,其中第 \(i*n+j\) 个表示的是已经使用了\(i\)次免费机会,目前在第 \(j\) 个实际节点的最短距离
这是一个分层的感觉,以只能用一次免费机会为例,没用过的是一张图,用过的是一张图,这每张图内部的边就按照题目信息连接就行
然后还有两张图之间的边,像这样,\(u',v'\)指的是用过免费机会以后的那个图:

\(u\rightarrow v',v\rightarrow u'\)的权值为\(0\),意思是花费\(0\)的代价可以用一次免费机会来走这些边
而在每张图内部的边权值是\(len\),意思时不花费免费机会需要用 \(len\) 的代价来走

然后跑一边 dij 就行,但是当他的终点是\(end\),实际路程要为:\(\min_{i=0}^k dis(i*n+end)\)
因为不一定每一次机会都要用

在我们构建的这张分层的图中,点数是 \((k+1)n\),边数是 \(m(2k+1)\)

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int n,m,k;
int start,end;
int nex[2100006],to[2100006],w[2100006];
int fir[110006],tot;
int heap[110006],size;
int dis[110006],in[110006];
inline void add(int u,int v,int len){
	to[++tot]=v;w[tot]=len;
	nex[tot]=fir[u];fir[u]=tot;
}
inline void link(int u,int v,int len){
	add(u,v,len);add(v,u,len);
}
inline void push(int x){
	heap[++size]=x;
	reg int i=size,fa;
	while(i>1){
		fa=i>>1;
		if(dis[heap[fa]]<=dis[heap[i]]) return;
		std::swap(heap[fa],heap[i]);i=fa;
	}
}
inline int pop(){
	int ret=heap[1];heap[1]=heap[size--];
	int i=1,ls,rs;
	while((i<<1)<=size){
		ls=i<<1;rs=ls|1;
		if(rs<=size&&dis[heap[rs]]<dis[heap[ls]]) ls=rs;
		if(dis[heap[ls]]>=dis[heap[i]]) break;
		std::swap(heap[i],heap[ls]);i=ls;
	}
	return ret;
}
inline int dij(){
	std::memset(dis,0x3f,sizeof dis);dis[start]=0;
	push(start);in[start]=1;
	while(size){
		reg int u=pop(),v;in[u]=0;
		for(reg int i=fir[u];i;i=nex[i]){
			v=to[i];
			if(dis[v]>dis[u]+w[i]){
				dis[v]=dis[u]+w[i];
				if(!in[v]) push(v),in[v]=1;
			}
		}
	}
	int ans=2e9;
	for(reg int i=0;i<=k;i++) ans=std::min(ans,dis[i*n+end]);
	return ans;
}
int main(){
	n=read(),m=read(),k=read();
	start=read()+1;end=read()+1;
	for(reg int u,v,len,i=1;i<=m;i++){
		u=read()+1;v=read()+1;len=read();
		link(u,v,len);
		for(reg int j=1;j<=k;j++) link(j*n+u,j*n+v,len),add((j-1)*n+u,j*n+v,0),add((j-1)*n+v,j*n+u,0);
	}
	std::printf("%d",dij());
	return 0;
}
posted @ 2020-04-13 10:49  suxxsfe  阅读(175)  评论(0编辑  收藏  举报