[分层图最短路][最短路变形]通信线路 AcWing340

在郊区有 N 座通信基站,P 条 双向 电缆,第 i 条电缆连接基站 Ai 和 Bi。

特别地,1 号基站是通信公司的总站,N 号基站位于一座农场中。

现在,农场主希望对通信线路进行升级,其中升级第 i 条电缆需要花费 Li。

电话公司正在举行优惠活动。

农产主可以指定一条从 1 号基站到 N 号基站的路径,并指定路径上不超过 K 条电缆,由电话公司免费提供升级服务。

农场主只需要支付在该路径上剩余的电缆中,升级价格最贵的那条电缆的花费即可。

求至少用多少钱可以完成升级。

输入格式

第 1 行:三个整数 N,P,K。

第 2..P+1 行:第 i+1 行包含三个整数Ai,Bi,Li。

输出格式

包含一个整数表示最少花费。

若 1 号基站与 N 号基站之间不存在路径,则输出 −1。

数据范围

0≤K<N≤1000,
1≤P≤10000,
1≤Li≤1000000

输入样例:

5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6

输出样例:

4

题意: 有一个n点m边的无向图,还拥有k次免费路径机会,求从点1到点n的所有路径中最大边的最小值。

分析: 分层图上求最短路问题,是[分层图最短路]飞行路线 洛谷P4568 这道题的升级版,飞行路线只需要求出在k次免费路径下剩余路径长度,这个是非常容易获得的,但这道题要求的是从1到n的所有路径上第k+1大边的最小值,这有点类似最短路变形题,不过所有的一切都是建立在分层图基础上的。分层图上的层数表示使用了几条免费路径到达某点,再结合一下最短路变形的思想,这道题也就是求从1到第k层上n的所有路径上最大边的最小值,只需修改dijkstra松弛条件为:

if(dis[to][c] > max(dis[now][c], e[i].w))
{
    dis[to][c] = max(dis[now][c], e[i].w);
    a.push(make_pair(dis[to][c], to+c*n));
}

之后在分层图上跑一个dijkstra,然后统计dis[n][i]的最小值即可。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#define int long long
#define pii pair<int, int>
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
//求从0到n-1的所有路径上第k+1大边的最小值 
//也就是从0到第k层上n-1的所有路径上最大边的最小值 
int n, m, k, head[1005], dis[1005][1005], cnt;//dis[i][j]表示到达i时使用了j次免费路径 
bool vis[1005][1005];
struct edge
{
	int to, next, w;
}e[20005];

void add(int u, int v, int w)
{
	e[++cnt].to = v;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt;
}

void dijkstra()
{
	memset(dis, 0x3f, sizeof dis);
	dis[0][0] = 0;
	priority_queue<pii, vector<pii>, greater<pii> > a;
	a.push(make_pair(dis[0][0], 0));
	while(a.size())
	{
		int now = a.top().second;
		int c = now/n;//表示在第几层上 
		now %= n;
		a.pop();
		if(vis[now][c]) continue;
		vis[now][c] = true;
		for(int i = head[now]; i; i = e[i].next)
		{
			int to = e[i].to;
			if(dis[to][c] > max(dis[now][c], e[i].w))
			{
				dis[to][c] = max(dis[now][c], e[i].w);
				a.push(make_pair(dis[to][c], to+c*n));
			}
		}
		if(c < k)
			for(int i = head[now]; i; i = e[i].next)
			{
				int to = e[i].to;
				if(dis[to][c+1] > dis[now][c])
				{
					dis[to][c+1] = dis[now][c];
					a.push(make_pair(dis[to][c+1], to+n*(c+1)));
				}
			}
	}
}

signed main()
{
	cin >> n >> m >> k;
	for(int i = 1; i <= m; i++)
	{
		int u, v, w;
		scanf("%lld%lld%lld", &u, &v, &w);
		u--, v--;
		add(u, v, w), add(v, u, w);
	}
	dijkstra();
	//枚举最小值是因为可能用不到k条免费路径就已经达到了0,之后会有一半情况为0,另一半不为0 
	int ans = inf;
	for(int i = 0; i <= k; i++)
		ans = min(dis[n-1][i], ans);
	if(ans == inf)
		puts("-1");
	else
		cout << ans << endl;
    return 0;
}

上一篇:Day1 课后总结


下一篇:SpringSecurity中文文档——Architecture