洛谷 P2939 [USACO09FEB]改造路Revamping Trails 题解

P2939 [USACO09FEB]改造路Revamping Trails

题目描述

Farmer John dutifully checks on the cows every day. He traverses some of the M (1 <= M <= 50,000) trails conveniently numbered 1..M from pasture 1 all the way out to pasture N (a journey which is always possible for trail maps given in the test data). The N (1 <= N <= 10,000) pastures conveniently numbered 1..N on Farmer John's farm are currently connected by bidirectional dirt trails. Each trail i connects pastures P1_i and P2_i (1 <= P1_i <= N; 1 <= P2_i <= N) and requires T_i (1 <= T_i <= 1,000,000) units of time to traverse.

He wants to revamp some of the trails on his farm to save time on his long journey. Specifically, he will choose K (1 <= K <= 20) trails to turn into highways, which will effectively reduce the trail's traversal time to 0. Help FJ decide which trails to revamp to minimize the resulting time of getting from pasture 1 to N.

TIME LIMIT: 2 seconds

输入格式

  • Line 1: Three space-separated integers: N, M, and K

  • Lines 2..M+1: Line i+1 describes trail i with three space-separated integers: P1_i, P2_i, and T_i

输出格式

  • Line 1: The length of the shortest path after revamping no more than K edges

题意翻译

约翰一共有N)个牧场.由M条布满尘埃的小径连接.小径可 以双向通行.每天早上约翰从牧场1出发到牧场N去给奶牛检查身体.

通过每条小径都需要消耗一定的时间.约翰打算升级其中K条小径,使之成为高 速公路.在高速公路上的通行几乎是瞬间完成的,所以高速公路的通行时间为0.

请帮助约翰决定对哪些小径进行升级,使他每天从1号牧场到第N号牧场所花的时间最短

输入输出样例

输入 #1

4 4 1
1 2 10
2 4 10
1 3 1
3 4 100

输出 #1

1

说明/提示

K is 1; revamp trail 3->4 to take time 0 instead of 100. The new shortest path is 1->3->4, total traversal time now 1.

【思路】

分层图 + dijkstra
一道分层图的裸题
如果想了解分层图请看这里
了解分层图

【题目大意】

从1到n跑
其中可以让k条路的耗时变为0
求最小耗时

【题目分析】

可以免去k条路
如果你是因为看到了电话线那道题里面四倍经验的帖子
所以才来做的这个题
那你有可能失望而归了
因为做电话线的大部分都是用的二分答案+SPFA
那里面的三道题的确都是和电话线一个知识点
不过这个知识点不是二分答案+SPFA而是分层图
分层图就是专门针对这种可以免去k条路问题的
不过需要开很大的内存
想了解分层图的话请看上面那个链接或者去看其他大佬的博客

【核心思路】

将题目给出的图建立k个
然后两个图之间连接的路都标为0
因为这两个图之间的路就是那高速路
第i个图就是建立i条高速路的情况
然后就是裸着跑dijkstra就好了
最后比较用了1-k条高速公路到达n掉里面花费最少的输出就完结撒花!!!

【完整代码】

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

using namespace std;
const int Max = 4200005;
const int M = 420005;
struct point
{
	int w;//路径的长度 
	int x;//点的标号 
	bool operator < (const point & xx)const
	{
		return xx.w < w;
	}
};
struct node
{
	int y,ne,z;
}a[Max];
int sum = 0,head[M];
void add(int x,int y,int z)
{
	a[++ sum].y = y;
	a[sum].ne = head[x];
	a[sum].z = z;
	head[x] = sum;
}
priority_queue<point>q;
int d[M];
bool use[M];
void dj()
{
	memset(d,0x3f,sizeof(d));
	d[1] = 0;
	q.push((point){0,1});
	while(!q.empty())
	{
		point qwq = q.top();
		q.pop();
		int x = qwq.x,w = qwq.w;
		if(use[x] == true)
			continue;
		else
			use[x] = true;
		for(register int i = head[x];i != 0;i = a[i].ne)
		{
			int awa = a[i].y;
			if(d[awa] > d[x] + a[i].z)
			{
				d[awa] = d[x] + a[i].z;
				if(use[awa] == false)
					q.push((point){d[awa],awa});
			}
		}
	}
}

int main()
{
	freopen("walk.in","r",stdin);
	int n,m,k;
	cin >> n >> m >> k;
	for(register int i = 1;i <= m;++ i)
	{
		int x,y,z;
		cin >> x >> y >> z;
		add(x,y,z),add(y,x,z);
		for(register int j = 1;j <= k;++ j)
		{
			add(j * n + x,j * n + y,z);
			add(j * n + y,j * n + x,z);
			add((j - 1) * n + x,j * n + y,0);
			add((j - 1) * n + y,j * n + x,0);
		}
	}
	dj();
	int M = 0x7fffffff;
	for(register int i = 0;i <= k;++ i)
		M = min(M,d[i * n + n]);
	cout << M << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/acioi/p/11716601.html