P4568 [JLOI2011] 飞行路线 分层图

题意分析

从s到t,其中可免费k条,求第k+1大的航线。

知识点

分层图

分层图多用于求最短路径,但是最短路径中可以有k条边的权值为0或特殊值。

即有k个机会使得走某些边不花费代价或花费特殊的代价,可以建立k张相同的该图,每张图之间用有边的点连接起来,其代价是0或是特殊的值。每向下走一层,就代表用了一次机会,使得当前的路花费为0或特殊值,最多可以走k次。

分层图的构建步骤可以描述为:
1、先将图复制成 k+1 份 (0 ~ k)
2、对于图中的每一条边 <u,v> 从 ui 到 vi+1 建立与题目所给操作相对应的边(i=0,1,…,k)

k代表了进行操作的次数,而每层之间点的关系代表了何时进行操作。
分层图的建图

for(int i = 0;i < m;i++)
	{
		cin >> a >> b >> c;
		add(a,b,c);	//关键的建图,各层内部正常建边
		add(b,a,c);
		for(int j = 1;j <= k;j++)	//从0到k层建k+1张图
		{
			add(j*n+a,j*n+b,c);	//每层内部正常建图
			add(j*n+b,j*n+a,c);
			//上层的点建立到下层的边权为0的边
			add((j-1)*n+a,j*n+b,0);	//各层之间从上到下建边花费为0
			add((j-1)*n+b,j*n+a,0);
		}
	}
  • 分层图的注意问题
  • (1)建多少条边
    由分层对图的边和点较多,所以开空间的时候一定要精确计算,避免空间爆炸和运行时错误。
    一般开这么大 E=(4k+2)∗m
    why?
    k 层图每层分别 m 条边,然后第 i 层到第 i+1 层每两层之间 m 条边,就是 2mk+2(k-1)*m 条,总共 m(4k-2)条

这个图的 k 次免费实际是代表 k+1 层,需要开 m(4k+2)

代码实现

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N = 2100010,INF = 0x3f3f3f3f;	//注意数据范围,经测验此题最多的边数达到了2100009
typedef pair<int,int> PII;

int n,m,k,s,t,dis[N];
int e[N],ne[N],w[N],h[N],idx;	
bool vis[N];
priority_queue<PII,vector<PII>,greater<PII> > q;	

void add(int a,int b,int c)	
{
	e[idx] = b;
	ne[idx] = h[a];
	w[idx] = c;
	h[a] = idx++;
}

void dijkstra(int s)	
{
	memset(dis,INF,sizeof dis);
	dis[s] = 0;
	q.push({0,s});
	while(!q.empty())
	{
		int u = q.top().second;
		q.pop();
		if(vis[u])
			continue;
		vis[u] = 1;
		for(int i = h[u]; ~i;i = ne[i])
		{
			int v = e[i];
			if(dis[v] > dis[u]+w[i])
			{
				dis[v] = dis[u]+w[i];
				q.push({dis[v],v});
			}
		}
	}
}

int main()
{
	int a,b,c;
	cin >> n >> m >> k >> s >> t;
	memset(h,-1,sizeof h);
	for(int i = 0;i < m;i++)
	{
		cin >> a >> b >> c;
		add(a,b,c);	
		add(b,a,c);
		for(int j = 1;j <= k;j++)	
		{
			add(j*n+a,j*n+b,c);
			add(j*n+b,j*n+a,c);
			add((j-1)*n+a,j*n+b,0);
			add((j-1)*n+b,j*n+a,0);
		}
	}
	for(int i = 0;i < k;i++)
		add(i*n+t,(i+1)*n+t,0);	//为防止使用小于k次权力就到达终点,在每层的终点间建花费为0的边连起来

	dijkstra(s);	//从起点s出发
	cout << dis[n*k+t] << endl;	//到k层的终点为答案

	return 0;
}

相关习题

https://www.luogu.com.cn/problem/P2939

U262134 通信线路
P4822 [BJWC2012] 冻结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值