湫湫买火车票 最短路

本文介绍了一个基于图论的最短路径算法的应用实例,通过构建城市间的连接图并赋予不同的权重,来解决从一个城市到另一个城市的最舒适旅行路径问题。算法区分了硬座和卧铺的不同舒适度,分别计算最小不舒适度。

Problem Description

  出门在外,最想念的还是家,对在深圳腾讯工作的HR湫湫来说,春节回家是一年中最期盼的事,不仅可以见到阔别已久的亲人,还能以相亲的名义调侃众多帅哥(她的内心告诉她:如果相亲能遇到参加过腾讯编程马拉松的同学,就直接把自己嫁了~)。
  同时,每年的春节湫秋也都会纠结一把,因为车票实在是太难抢了,不过2013的春节有点特殊,作为一个曾经的ACMer,湫湫制作出了很完美的刷票机,也就是说她再也不用担心买不上票了,但是想来想去还是觉得随便买票实在是浪费了辛辛苦苦搞出来的刷票机,所以她决定要用最舒适的方式回家。
  假设湫湫有可能经过的n个城市分别编号从1到n,湫湫要从城市A回到城市B,购票网站上列出了t辆列车行程,每辆车的行程用一个字符串表示,途径的城市间用+号相连,如1+2+3+5代表一辆从1城市分别经过2,3到达5的火车,湫湫可以从中间任意一站出发和下车(路径是单向的,即必须沿字符串从左到右来走),每个字符串对应着一个整数k,k=0表示该车只有硬座,k=1表示该车有卧铺也有硬座,在整个回家的计划中,同一辆车可以坐无限次,为了中途换车的方便,如果在起点坐的是卧铺,则后面乘坐的车必须全是卧铺,同样的,如果在起点坐的是硬座,则后面乘坐的车必须全是硬座,假设一段(一辆车行程中,两相邻城市间为一段)硬座的不舒适度是D1,一段卧铺的不舒适度是D2,求湫湫回家最小的不舒适度。

Input

  输入数据的第一行包含一个整数Q,表示测试数据的组数;
  每组数据的第一行是2个正整数n和t,分别表示城市数和列车数;
  接下来t行,每行一个字符串表示列车行程,字符串长度小于10000,每个字符串后跟一个整数k(k为0或1),之间用空格隔开;
  接下来一行是D1,D2,其含义见题目描述;
  最后一行是2个正整数A和B,表示起始和终点城市。

  [TechnicalSpecification]
  1 <= Q <= 100
  1 < n <= 200
  1 < t <= 1000
  0 < D1 <= 10000, 0 < D2 <= 10000,D1和D2的大小关系不确定
  1 <= A, B <= n 且 A<> B

Output

  对于每组数据,如果湫湫可以到达目的地,则输出一个整数,表示湫湫到家所需的最小不舒适度。如果不能到达则直接输出-1。

Sample Input

1
6 5
2+4+3+5+1+6 1
5+4+2+3+1 1
3+2+5+1+6 1
6+2 0
6+3+1+4+5+2 0
3 2
5 3

Sample Output

4

 

给出火车经过的站点,和火车上现有的座位类型硬座和卧铺,并给出不同座位类型的舒适度,求出起点到终点的最小不舒适度                                                                                                                                                                                                                                                         

对硬座和卧铺分别求最短路,然后比较出最小不舒适度

题目给出的是火车经过的站点并没有明确给出距离,需要根据给出的字符串来确定距离才能应用最短路,并且1的时候既有硬座也有卧铺,不要忽略了硬座,如果硬座都不能到达的话则说明不能到站,否则判断两种不同的出行方式的最小不舒适度

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 0X3fffffff
int map[1010][1010],map1[1010][1010],dis[1010],dis1[1010],n,s,e;
void f()
{
	int i,j,min,k;
	int vis[1010]={0};
	for(i=1;i<=n;i++)
		dis[i]=map[s][i];
	vis[s]=1;
	dis[s]=0;
	for(i=1;i<n;i++)
	{
		min=inf;
		k=1;
		for(j=1;j<=n;j++)
		{
			if(!vis[j] && dis[j]<min)
			{
				min=dis[j];
				k=j;
			}
		}
		vis[k]=1;
		for(j=1;j<=n;j++)
			if(!vis[j] && dis[j]>dis[k]+map[k][j])
				dis[j]=dis[k]+map[k][j];
	 } 	 
}
void f1()
{
	int i,j,min,k;
	int vis[1010]={0};
	for(i=1;i<=n;i++)
		dis1[i]=map1[s][i];
	vis[s]=1;
	dis1[s]=0;
	for(i=1;i<n;i++)
	{
		min=inf;
		k=1;
		for(j=1;j<=n;j++)
		{
			if(!vis[j] && dis1[j]<min)
			{
				min=dis1[j];
				k=j;
			}
		}
		vis[k]=1;
		for(j=1;j<=n;j++)
			if(!vis[j] && dis1[j]>dis1[k]+map1[k][j])
				dis1[j]=dis1[k]+map1[k][j];
	 } 
}
int main()
{
	int t,m,len,i,j,d1,k,d2,p[10010];
	char str[10010];
	scanf("%d",&t);
	while(t--)
	{
		memset(dis,0,sizeof(dis));
		memset(dis1,0,sizeof(dis1));
		memset(map,0,sizeof(map));
		memset(map1,0,sizeof(map1));
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
				map[i][j]=inf;
		for(i=1;i<=n;i++) 
			for(j=1;j<=n;j++)
				map1[i][j]=inf;
		for(i=0;i<m;i++)
		{
			memset(p,0,sizeof(p));
			scanf("%s",str);
			len=strlen(str);
			str[len]='+';
			str[len+1]='\0';
			int a=0,f=0,flag;
			for(j=0;j<=len;j++)
			{
				if(str[j]=='+'){
					p[f]=a;
					f++;
					//printf("%d ",a);
					a=0;
				}
				else
					a=a*10+str[j]-'0';
			}
			scanf("%d",&k);
			if(k==1){
				flag=1;
				for(j=0;j<f;j++){
					for(k=j+1;k<f;k++){
						if(map[p[j]][p[k]]>flag)
							map[p[j]][p[k]]=flag;
						if(map1[p[j]][p[k]]>flag)
							map1[p[j]][p[k]]=flag;
						flag++;
					}	
					flag=1;
				}	
			}
			else{
				flag=1;
				for(j=0;j<f;j++){
					for(k=j+1;k<f;k++){
						if(map1[p[j]][p[k]]>flag)
							map1[p[j]][p[k]]=flag;
						flag++;
					}
					flag=1;
				}	
			}
		}
		scanf("%d%d",&d1,&d2);
		scanf("%d%d",&s,&e);	
		f();
		f1();
//		printf("%d\n",dis[e]);
//		printf("%d\n",dis1[e]);
		if(dis1[e]==inf)
			printf("-1\n");
		else
		{
			if(dis[e]==inf)
				printf("%d\n",dis1[e]*d1);
			else
			{
				if(dis1[e]*d1<dis[e]*d2)
					printf("%d\n",dis1[e]*d1);
				else
					printf("%d\n",dis[e]*d2);
			}
		}
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值