bzoj1579

基于分层图的最短路
对于分成图建图的时候如果真要建的话一定要注意层与层之间是单向路而且一个边的两个端点都要建边,通常我们范的错误就是只建from->to的一条一定不要忘了to->from 这题很简单就是一个dp+最短路,不用建图但思想一样
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
struct nodee
{
	int name, kind;
	ll dis;
};
nodee node[20000];
int first[20000], nextt[150000];
ll dis[20000][21];
int n, m, k;
struct edgee
{
	int from, to;
	ll dis;
	edgee(int from, int to, ll dis) :from(from), to(to), dis(dis)
	{}
	edgee()
	{}
};
edgee edge[150000];
int edgetot;
void addedge(int from, int to, ll dis)
{
	edge[edgetot] = edgee(from, to, dis);
	nextt[edgetot] = first[from];
	first[from] = edgetot++;
	edge[edgetot] = edgee(to, from, dis);
	nextt[edgetot] = first[to];
	first[to] = edgetot++;
}
struct com
{
	bool operator()(nodee a, nodee b)
	{
		return a.dis > b.dis;
	}
};
void distra()
{
	priority_queue < nodee, vector<nodee>, com > que;
	dis[1][1] = 0;
	nodee a;
	a.dis = 0; a.kind = 1; a.name = 1;
	que.push(a);
	while (!que.empty())
	{
		nodee now = que.top();
		que.pop();
		if (now.dis > dis[now.name][now.kind])
			continue;
		for (int i = first[now.name]; i != -1; i = nextt[i])
		{
			int to = edge[i].to;
			if (dis[to][now.kind] > dis[now.name][now.kind]+edge[i].dis)
			{
				dis[to][now.kind] = dis[now.name][now.kind] + edge[i].dis;
				nodee c;
				c.dis = dis[to][now.kind]; 
				c.kind = now.kind; 
				c.name = to;
				que.push(c);
			}
			if (dis[to][now.kind + 1] > dis[now.name][now.kind] && now.kind + 1<=k)
			{
				nodee c;
				dis[to][now.kind + 1] = dis[now.name][now.kind];
				c.name = to; 
				c.dis = dis[now.name][now.kind]; 
				c.kind = now.kind + 1;
				que.push(c);
			}
		}
	}
}
int main()
{
	scanf("%d%d%d", &n, &m, &k);
	k++;
	for (int i = 1; i <= n; i++)
		first[i] = -1;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= k; j++)
			dis[i][j] = 1000000000000;
	}
	for (int i = 0; i < m; i++)
	{
		int a, b;
		ll c;
		scanf("%d%d%lld", &a, &b, &c);
		addedge(a, b, c);
	}
	distra();
	printf("%lld\n", dis[n][k]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值