HDU 4725 The Shortest Path in Nya Graph(堆优化dijkstra)

题目链接:【HDU 4725】

n个点分布在n层上,同一层内任意点之间的花费是0,从第i层的任意一个点到第i+1层的任意一个点需要花费c,m条路径,每条路径包括u、v、w,表示在点u,v之间来回需要花费w,问能否从从点1走到到点n,能的话输出最小花费,不能的话就输出-1

将一层看做两个点,第i层对应n+2*i-1、n+2*i,一个点是出去的,一个点是进来的

举个例子:

一共是3个点,即n=3,第3个点在第二层上,建图的时候就是 3 ==> 6 &&7 ==> 3,并且点3跟点6之间的花费是0,点7跟点3之间的花费也是0

然后将第i层与第i+1层连起来,他们之间的花费是c,也就是第i层出去的点指向第i+1层进来的点,第i层进来的点指向第i+1层出去的点,接下来就是堆优化的dijkstra

每一层为什么不转化为1个点的原因:每一层如果都是转化为一个点,那实际存在的点与层转化过来的点之间就是双向的,而不是单向的,这样建图会出问题的,比如点1和点2都在层5上,会出现图中的情况,点1到点2的最终花费会变成0

             

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
using namespace std;
const int inf=1e5+10;
const int maxn=0x3f3f3f3f;
int t, n, m, c, p, cas;
struct node
{
	int v, w;
	node(int vi, int wi) : v(vi), w(wi) {}
	friend bool operator < (const node n1, const node n2)
	{
		return n1.w>n2.w;
	}
};
vector<node>vec[inf*3];
int vis[inf*3], dis[inf*3];
void dij()
{
	priority_queue<node>q;
	memset(dis, 0x3f3f3f3f, sizeof(dis));
	dis[1]=0;
	q.push(node(1,0));
	while(!q.empty())
	{
		node s=q.top();q.pop();
		int u = s.v, wi=s.w;
		if(vis[u]==cas) continue;
		vis[u] = cas;
		for(int i=0; i<vec[u].size(); i++)
		{
			node e=vec[u][i];
			if(vis[e.v]!=cas && dis[e.v]>dis[u]+e.w)
			{
				dis[e.v]=dis[u]+e.w;
				q.push(node(e.v, dis[e.v]));
			}
		}
	}
}
void add(int u, int v, int wi)
{
	vec[u].push_back(node(v, wi));
}
int main()
{
	scanf("%d", &t);
	cas=1;
	while(t--)
	{
		scanf("%d%d%d", &n, &m, &c);
		for(int i=1; i<=3*n; i++) vec[i].clear();
		for(int i=1; i<=n; i++)//层上的点与层之间的单向连接  
		{
			scanf("%d", &p);
			add(i, n+2*p-1,0);
			add(n+2*p, i, 0);
		}
		for(int i=1; i<n; i++)//层与层之间的单向连接 
		{
			add(n+2*i-1, n+2*(i+1), c);
			add(n+2*(i+1)-1, n+2*i, c);
		}
		for(int i=0; i<m; i++)
		{
			int u,v, wi;
			scanf("%d%d%d", &u, &v, &wi);
			add(u,v,wi);
			add(v,u,wi);
		} 
		dij();
		int ans=dis[n];
		printf("Case #%d: %d\n", cas++, (ans==maxn ? -1:ans));
	}
	return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值