SWUN 1454 - Hotel booking

22 篇文章 0 订阅
2 篇文章 0 订阅

 


Hotel booking

时间限制(普通/Java) : 4000 MS/ 10000 MS          运行内存限制 : 65536 KByte
总提交 : 1            测试通过 : 1

描述

    A transport company often needs to deliver goods from one city to another city. The transport company has made a special deal with a hotel chain which allows its drivers to stay in the hotels of this chain for free. Drivers are only allowed to drive up to 10 hours a day. The transport company wants to find a route from the starting city to the destination city such that a driver can always spend the night in one of the hotels of the hotel chain, and that he needs to drive at most 10 hours from one hotel to the next hotel (or the destination). Of course, the number of days needed to deliver the goods should also be minimized.

输入

    The input file contains several test cases. Each test case starts with a line containing an integer n, (2 ≤ n ≤ 10000), the number of cities to be considered when planning the route. For simplicity, cities are numbered from 1 to n, where 1 is the starting city, and n is the destination city. The next line contains an integer h followed by the numbers c1, c2, ..., ch indicating the numbers of the cities where hotels of the hotel chain are located. You may assume that 0 ≤ h ≤ min(n, 100). The third line of each test case contains an integer m (1 ≤ m ≤ 105), the number of roads to be considered for planning the route. The following m lines describe the roads. Each road is described by a line containing 3 integers a, b, t (1 ≤ a, b ≤ n and 1 ≤ t ≤ 600), where a, b are the two cities connected by the road, and t is the time in minutes needed by the driver to drive from one end of the road to the other. Input is terminated by n = 0.

输出

    For each test case, print one line containing the minimum number of hotels the transport company has to book for a delivery from city 1 to city n. If it is impossible to find a route such that the driver has to drive at most 10 hours per day, print -1 instead.

样例输入

6
3 2 5 3
8
1 2 400
3 2 80
3 4 301
4 5 290
5 6 139
1 3 375
2 5 462
4 6 300
3
0
2
1 2 371
2 3 230
0

样例输出

2
-1

提示

 

题目来源

University of Ulm


 

题目地址: http://218.194.91.48/acmhome/problemdetail.do?&method=showdetail&id=1454

 

二维spfa,优先队列优化。 (其实我就是当作BFS来做,只不过做法类似spfa)

 

 

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

using namespace std;

struct Edge{
	int nx,cost,v;
}edge[210000];
int ef[10010],tol=0;

void add_edge(int a,int b,int cost){
	edge[tol].v=b;
	edge[tol].cost=cost;
	edge[tol].nx=ef[a];
	ef[a]=tol++;
}

struct Node{
	int u,minute,vis;
	Node(){};
	Node(int uu,int mm,int vv){
		u=uu; // 当前所在位置
		minute=mm; // 记录从旅馆/起点出发,到达u位置所花费的最时间
		vis=vv; // 记录入住次数
	}
	bool friend operator<(Node a,Node b){ // 优先级为: 访问旅馆次数较少的点先走,次数相同则以花费时间少的点先走
		return a.vis!=b.vis?a.vis>b.vis:a.minute>b.minute;
	}
};

priority_queue<Node>que;

int n;

int has[10010];
int Time[10010]; // Time[v]记录【v位置】与 【起点/最近的旅馆】 的最短距离
int Count[10010]; // Count记录当前已入住的次数
int spfa(){
	int k,v,tmp;
	Node now,nx;
	que.push(Node(1,0,0));
	while(!que.empty()){
		now=que.top();
		que.pop();
		if(now.u==n) return now.vis;
		for(k=ef[now.u];k!=-1;k=edge[k].nx){
			v=edge[k].v;
	 		if(Count[v]<now.vis){ // 当访问旅馆次数增加,那么之前记录的时间作废 
	 			Count[v]=now.vis;
		 		Time[v]=601; // 重新记录时间为601分钟 
		 	}
	 		tmp=now.minute+edge[k].cost; // 从【起点/旅馆】出发,到达v时所花费的时间 
	 		if(tmp>=Time[v] || has[v]==-1) continue; // 时间比记录的Time[v]还高,那么不再访问 
	 		Time[v]=tmp;
	 		que.push(Node(v,tmp,now.vis));
			if(has[v]==1){ // 一开始写在continue那句之前,样例都没过,囧 
	 			has[v]=-1; // 标记住过的旅馆不再住,(为何?既然之前更优的走法先入住了,现在更搓的走法何必再入住。可以仔细想哈)
	 			que.push(Node(v,0,now.vis+1));
	 		}
		}
	}
	return -1;
}

void INIT(){
	int i;
	for(i=1;i<=n;i++){
		has[i]=0;
		ef[i]=Count[i]=-1;
	}
	tol=0;
	while(!que.empty()) que.pop();
}

int main(){
	int m,a,b,len;
	while(~scanf("%d",&n)){
		if(!n) break;
		INIT();
		scanf("%d",&m);
		while(m--){
			scanf("%d",&a);
			has[a]=1;
		}
		scanf("%d",&m);
		while(m--){
			scanf("%d%d%d",&a,&b,&len);
			add_edge(a,b,len);
			add_edge(b,a,len);
		}
		printf("%d\n",spfa());
	}	
	return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值