【AHOI2002】哈利●波特与魔法石

题目背景
AHOI2002 DAY2 T2


题目描述
某天,哈利•波特准备去拯救 Super Swamuel 星球上的生灵。该星球上有七种不同的地形,依次分别是:石子路、森林、草地、山地、雪地、沼泽和沙漠。分别用数字 1~7 来表示,穿越这七种地形需要的时间分别用 h1~h7 表示。


任意两个城市之间都存在至少一条通路,而且任意两个直通的城市之间都只存在一种地形。哈利•波特穿越地形 u 所需要的时间与该地形的区域大小无关,而与地形 u 的区域中是否有魔法石有关。如果地形 u 的区域中没有魔法石,哈利•波特需要花费 hu 的时间能穿越该地区;如果他有魔法石,则只要花一半的时间(hu/2)就能穿越地形 u。这里 hu/2 用整除法。


已知没有魔法石的情况下穿越七种地形需要的时间分别如下表格:


地形名称 石子路 森林 草地 山地 雪地 沼泽 沙漠
地形编号(i) 1 2 3 4 5 6 7
穿越时间(hi) 2 6 4 8 6 10 14
哈利•波特将从城市 i 出发到城市 j 去伸张正义,请你帮他寻找出最快的路线。


输入格式
第一行有七个整数 s1~s7 ,分别表示七种地形中是否有魔法石,su=0 表示地形 u 的区域中没有魔法石;su=1 表示地形 u 的区域中有魔法石。su ∈{0,1}
第二行有两个正整数,分别是起点 i 的编号和终点 j 的编号。
第三行有一个正整数 m(m≤10000),表示以下有 m 对直接相连的城市。
随后 m 行,每行三个正整数 i,j,k,分别是城市 i 与城市 j 之间连通,这两个城市之间的地形是 k,其中:0<i,j≤1000,k∈{1,2,3,4,5,6,7} ,地形编号意义请参考“题目描述”中的表格。


输出格式
输出一个整数,即穿越起点城市 i 与终点城市 j 之间的地形需要的最短时间。


样例数据 1
输入  [复制] 


0 1 0 0 0 0 0 
1 4 

1 2 1 
1 3 1 
2 4 2 
3 4 3
输出


5
备注
【样例说明】

从路径 1→2→4 穿越,需要的最短时间是:2+(6/2)=5


----------------------------------------------------------------------------------------------------------------------------------

最短路裸题!

我用的是dijkstra领接表+堆优化

据说Floyd都能过...

但是我发现自己隔了一个月没碰的东西就有点忘了 这里总结一下dijkstra堆优化的思路

(PS 像这种无向图!!!需要add两次!!!!!!!卡了好久)

dijkstra算法的核心——对于每个点——找当前点相连的点离起点最近的点——从这个点出发松弛——如果相连的点在集合里,且当前路径优于之前路径那么替换

建立priority_queue<make_pair<int int> > 第一个存路径长度 第二存对应的点

 对于当前的点 先从priority_queue里取出离起点路径最短的一个点 (这个操作 在原版dijkstra中是最费时间的)从这个点向它相连的边遍历 进行松弛操作


okok看代码


#include<bits/stdc++.h>
using namespace std;

const int INF=0x7fffffff;
int start,end,m;
int x,y,z; 
int t[8]={0,2,6,4,8,6,10,14};

int to[10005],first[1005],next[10005],v[10005],tot,dis[1005];
priority_queue <pair<int,int> > q;

void add(int x,int y,int ooo)
{
	tot++;
	next[tot]=first[x];
	first[x]=tot;
	to[tot]=y;
	v[tot]=ooo;
}

void dijkstra()
{
	dis[start]=0;
	q.push(make_pair(0,start));
	while(!q.empty())
	{
		int k=q.top().second;
		q.pop();
		for(int i=first[k];i;i=next[i])
		{
			int f=to[i];
			if(dis[k]+v[i]<dis[f])
			{
				dis[f]=dis[k]+v[i];
				q.push(make_pair(-dis[f],f));
			}
		}
	}
}
int main()
{
	for(int i=1;i<=7;i++)
	{
		int is_stone;
		cin>>is_stone;
		if(is_stone==1) t[i]=t[i]/2;
	}
	cin>>start>>end;
	cin>>m;
	
	for(int i=1;i<=1005;i++)
	{
		dis[i]=INF;
	}
	
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y>>z;
		add(x,y,t[z]);//记得两次!!!!!!!!!!!!!!!!! 
		add(y,x,t[z]);
	}
	dijkstra();
	cout<<dis[end]<<endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值