LG·飞行路线【分层图最短路】

本文介绍了一道名为“飞行路线”的算法题目,涉及多个城市间的航线与费用计算。通过建立多层图并运用Dijkstra算法求解最小花费路径,适用于算法竞赛和图论学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description–

一共有 n n n 个城市,分别标记为 0 0 0 n − 1 n-1 n1,一共有 m m m 种航线,每种航线连接两个城市,并且航线有一定的价格,可以免费在最多 k k k 种航线上搭乘飞机。

花费多少?


Input–

第一行三个整数 n , m , k n,m,k n,m,k,分别表示城市数,航线数,免费乘坐次数

接下来一行两个整数 s , t s,t s,t,分别表示起点城市和终点城市

接下来 m m m 行,每行三个整数 a , b , c a,b,c a,b,c,表示存在一种航线,能从城市 a a a 到达城市 b b b,或从城市 b b b 到达城市 a a a,价格为 c c c

Output–

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


Sample Input–

5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100

Sample Output–

8

说明–

在这里插入图片描述


解题思路–

模板题

建图的时候建成 k k k 层,每下一层无需代价,再跑一遍最短路(要用dij,spfa会被卡
答案在第 k k k 层的终点


代码–

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

using namespace std;

int n, m, k, s, t, a, b, c, cnt;
int ls[2100000], dis[2100000];
bool pd[2100000];

struct hll
{
	int x, y, next;
}f[5100000];

struct node
{
	int x, y;
	friend bool operator < (node xx, node yy)
	{
		return xx.y > yy.y;
	}
};

priority_queue<node> q;

void add(int xx, int yy, int zz)
{
	f[++cnt] = (hll){yy, zz, ls[xx]}, ls[xx] = cnt;
}

void dij()
{
	memset(dis, 0x7f, sizeof(dis));
	dis[s] = 0, q.push((node){s, 0});
	while (!q.empty())
	{
		node u = q.top();
		q.pop();
		if (pd[u.x]) continue;
		pd[u.x] = 1;
		for (int i = ls[u.x]; i; i = f[i].next)
		  if (!pd[f[i].x] && dis[u.x] + f[i].y < dis[f[i].x])
		  {
		  	  dis[f[i].x] = dis[u.x] + f[i].y;
		  	  q.push((node){f[i].x, dis[f[i].x]});
		  }
	}
}

int main()
{
	scanf("%d%d%d", &n, &m, &k);
	scanf("%d%d", &s, &t);
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d%d%d", &a, &b, &c);
		add(a, b, c), add(b, a, c);
		for (int j = 1; j <= k; ++j)
		{
			add(a + (j - 1) * n, b + j * n, 0); //下一层无需代价
			add(b + (j - 1) * n, a + j * n, 0);
			add(a + j * n, b + j * n, c);
			add(b + j * n, a + j * n, c);
		}
	}
	for (int i = 1; i <= k; ++i) //把每一层的终点连起来
	  add(t + (i - 1) * n, t + i * n, 0);
	dij();
	printf("%d", dis[t + k * n]);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值