最短路 Dijkstra ACM-ICPC 2018 南京赛区网络预赛 K Magical Girl Haze

魔法少女Haze从城市1出发前往城市N,可通过将不超过K条道路的距离设为0来缩短行程。本篇介绍如何利用Dijkstra算法及优先队列优化找到最短路径。

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

K Magical Girl Haze

There are N cities in the country, and M directional roads from u to v(1≤u,v≤n). Every road has a distance ci​. Haze is a Magical Girl that lives in City 1, she can choose no more than K roads and make their distances become 0. Now she wants to go to City N, please help her calculate the minimum distance.

Input

The first line has one integer T(1≤T≤5), then following T cases.

For each test case, the first line has three integers N, M and K.

Then the following M lines each line has three integers, describe a road, Ui​,Vi​,Ci​. There might be multiple edges between u and v.

It is guaranteed that N≤100000,M≤200000,K≤10,
0≤Ci​≤1e9. There is at least one path between City 1 and City N.

Output

For each test case, print the minimum distance.

样例输入

1
5 6 1
1 2 2
1 3 4
2 4 3
3 4 1
3 5 6
4 5 2

样例输出

3

题目来源

ACM-ICPC 2018 南京赛区网络预赛

 

题目大意:haze要从城市1走到城市n,她可以使最多k条路的路长变为0,问她至少要走多少距离。

 

最短路问题,因为k<=10,所以考虑可以将d数组开成二位进行最短路算法:

嘛要用堆优化(优先队列),3个状态转移/更新  1到v有最多j条路化为0  的最小值:

d[v][j]=min(d[v][j],d[u][j-1]);    //1到u有最多j-1条路化为0,u-v化为0
d[v][j]=min(d[v][j],d[v][j-1]);    //1到v有最多j条路化为0,最多有j-1条路化为0(路的条数<j)
d[v][j]=min(d[v][j],d[u][j]+c);     //1到u有最多j条路化为0,则1到v最多有j条路化为0还要再加上c(u,v)

取其中最小值。

 

思路清晰+最短路堆优化Dijkstra=AC

 

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn=1e5+10;
const int maxk=11;
const int maxm=2e5+10;
const long long inf=0x3f3f3f3f3f3f;

int n,m,k;
long long d[maxn][maxk];

struct node{
	int v;
	long long c;
	node(int a,long long b):v(a),c(b){}
};

struct p{
	int u,k;
	long long dis;
	p(int a,int b,long long c):u(a),k(b),dis(c){}
	friend bool operator < (p a,p b)
	{
		return a.u>b.u;
	}
};

vector <node> r[maxn];

void dijkstra()
{
	priority_queue <p,vector<p>,less<p> > q;
	for(int i=2;i<=n;++i)
		for(int j=0;j<=k;++j)
			d[i][j]=inf;
	q.push(p(1,0,0));
	while(!q.empty()){
		p now=q.top();
		q.pop();
		int u=now.u;
		int z=now.k;
		if(d[u][z]<now.dis) continue;
		int sz=r[u].size();
		for(int i=0;i<sz;++i){
			int v=r[u][i].v;
			long long c=r[u][i].c;
			for(int j=z;j<=k;++j){
				long long pre=d[v][j];
				if(j) {
					d[v][j]=min(d[v][j],d[u][j-1]);
					d[v][j]=min(d[v][j],d[v][j-1]);
				}
				d[v][j]=min(d[v][j],d[u][j]+c);
				if(d[v][j]<pre) q.push(p(v,j,d[v][j]));
			}
		}
	}
}

int main()
{
	int t;
	int u,v;
	long long c;

	scanf("%d",&t);
	for(int j=0;j<=k;++j)
		d[1][j]=0;
	while(t--){
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=n;++i)
			r[i].clear();
		for(int i=0;i<m;++i){
			scanf("%d%d%lld",&u,&v,&c);
			r[u].push_back(node(v,c));
		}
		dijkstra();
		printf("%lld\n",d[n][k]);
	}

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值