【题解 && 海量集训 && 最短路】 Airport Express

10 篇文章 0 订阅
题目传送门

题目描述:

|中文|

在IokhIokhIokh市中,机场快线是市民从市内去机场的首选交通工具。机场快线分为经济线和商业线两种,线路、速度和价钱都不同。你有一张商业线车票,可以坐一站商业线,而其他时候只能乘坐经济线。假设换乘时间忽略不计,你的任务是找一条去机场最快的线路。
输入格式:
输入包含多组数据。每组数据第一行为333个整数N,SN, SN,S和E(2≤N≤500,1≤S,E≤100)E(2 \leq N \leq 500, 1 \leq S, E \leq 100)E(2≤N≤500,1≤S,E≤100),即机场快线中的车站总数,起点和终点(即机场所在站)编号。下一行包含一个整数M(1≤M≤1000)M(1 \leq M \leq 1000)M(1≤M≤1000),即经济线的路段条数。以下MMM行每行3个整数X,Y,Z(1≤X,Y≤N,1≤Z≤100)X, Y, Z(1 \leq X, Y \leq N, 1 \leq Z \leq 100)X,Y,Z(1≤X,Y≤N,1≤Z≤100),表示可以乘坐经济线在车站XXX和车站YYY之间往返,其中单程需要ZZZ分钟。下一行为商业线的路段条数K(1≤K≤1000)K(1 \leq K \leq 1000)K(1≤K≤1000),以下KKK行是这些路段的描述,格式同经济线。所有路段都是双向的,但有可能必须使用商业车票才能到达机场。保证最优解唯一。
输出格式:
对于每组数据,输出333行。第一行按访问顺序给出经过的各个车站(包括起点和终点),第二行是换乘商业线的车站编号(如果没有商业线车票,输出Ticket Not Used),第三行是总时间。

|英文|

In a small city called Iokh, a train service, Airport-Express,takes residents to the airport more quickly than other transports. There are two types of trains in Airport-Express,the Economy-Xpress and the Commercial-Xpress. They travel at different speeds, take different routes and have different costs.Jason is going to the airport to meet his friend. He wants to take the Commercial-Xpress which is supposed to be faster,but he doesn’t have enough money. Luckily he has a ticket for the Commercial-Xpress which can take him one station forward. If he used the ticket wisely, he might end up saving a lot of time. However, choosing the best time to use the ticket is not easy for him.Jason now seeks your help. The routes of the two types of trains are given. Please write a program to nd the best
route to the destination. The program should also tell when the ticket should be used.


分析:跑两遍dj,预处理出起点和终点到每个端点的距离,处理的时候处理一下点的前驱和后继。然后枚举每一个商业线,将加入商业线之后的长度与ans比较,然后记录商业线的编号。输出时按照商业线的编号再按照它的前驱和后继输出即可(输出后继时需要倒得输出)。

预处理完dj后,就可以O(1)判断出加入商业线之后的时间:
m i n ( d i s 1 [ u [ i ] ] + d i s 2 [ v [ i ] ] + u v [ i ] , d i s 1 [ v [ i ] ] + d i s 2 [ u [ i ] ] + u v [ i ] ) min(dis1[u[i]]+dis2[v[i]]+uv[i],dis1[v[i]]+dis2[u[i]]+uv[i]) min(dis1[u[i]]+dis2[v[i]]+uv[i],dis1[v[i]]+dis2[u[i]]+uv[i])
备注:其中dis1是当前点到端点的最短路,dis2是当前点到终点的最短路,u[i]和v[i]分别是商业线的两端,uv[i]是乘坐商业线的长度

那么具体代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>               
#include <stdio.h>
#include <string.h>
using namespace std;
typedef pair<int , int > pii;
int linkk1[10001],linkk2[10001];
int n,s,e;
bool f;
struct node{
    int y,Next,v;
}e1[10001],e2[10001];
int m1;
int last[10001],Next[10001];
int dis1[10001],dis2[10001];
int len1,len2;
bool vis[1001];
int u[1001],v[1001],uv[1101];
int k;
int m[1001];
void insert1(int x,int y,int z){
    e1[++len1].Next=linkk1[x];
    linkk1[x]=len1;
    e1[len1].y=y;
    e1[len1].v=z;
}
void insert2(int x,int y,int z){
    e2[++len2].Next=linkk2[x];
    linkk2[x]=len2;
    e2[len2].y=y;
    e2[len2].v=z;
}
int main(){
//	freopen("1.in","r",stdin);
//	freopen("1.out","w",stdout);
    while ((~scanf("%d %d %d",&n,&s,&e))&&n&&s&&e){
    	if (f) printf("\n");
    	f=1;
    	len1=len2=0;
    	memset(linkk1,0,sizeof(linkk1));
    	memset(linkk2,0,sizeof(linkk2));
    	memset(e1,0,sizeof(e1));
    	memset(e2,0,sizeof(e2));
        scanf("%d",&m1);
        for (int i=1,x,y,z;i<=m1;i++) scanf("%d %d %d",&x,&y,&z),insert1(x,y,z),insert1(y,x,z),insert2(y,x,z),insert2(x,y,z);
        scanf("%d",&k);
    	for (int i=1;i<=k;i++) scanf("%d %d %d",&u[i],&v[i],&uv[i]);
    	priority_queue < pii , vector < pii > , greater < pii > > q;
   		memset(dis1,20,sizeof(dis1));
   		memset(vis,0,sizeof(vis));
		dis1[s]=0;
		last[s]=0;
    	q.push(make_pair(0,s));
    	while (!q.empty()){
	    	pii t=q.top();q.pop();
	    	int x=t.second,vv=t.first;
//	    	printf("x:%d v:%d\n",x,vv);
	    	if (vis[x]) continue;
	    	vis[x]=1;
	    	for (int i=linkk1[x];i;i=e1[i].Next)
	      	if (dis1[e1[i].y]>vv+e1[i].v)
	          last[e1[i].y]=x,dis1[e1[i].y]=vv+e1[i].v,q.push(make_pair(dis1[e1[i].y],e1[i].y));
		}
//		for (int i=1;i<=n;i++) cout<<dis1[i]<<' '<<last[i]<<endl;
		memset(vis,0,sizeof(vis));
		memset(dis2,20,sizeof(dis2));
		Next[e]=0;
		dis2[e]=0;
		q.push(make_pair(0,e));
		while (!q.empty()){
	    	pii t=q.top();q.pop();
	    	int x=t.second,vv=t.first;
//	    	printf("x:%d v:%d\n",x,vv);
	    	if (vis[x]) continue;
	   	 	vis[x]=1;
	   		for (int i=linkk2[x];i;i=e2[i].Next)
	      	  if (dis2[e2[i].y]>vv+e2[i].v)
	          Next[e2[i].y]=x,dis2[e2[i].y]=vv+e2[i].v,q.push(make_pair(dis2[e2[i].y],e2[i].y));
		}
		int ans=dis1[e];
		int w=0;
		int f1=0,f2=0;
		for (int i=1;i<=k;i++){
		    if (ans>dis1[u[i]]+dis2[v[i]]+uv[i])
		      ans=dis1[u[i]]+dis2[v[i]]+uv[i],f1=u[i],f2=v[i];
		    if (ans>dis2[u[i]]+dis1[v[i]]+uv[i])
		      ans=dis2[u[i]]+dis1[v[i]]+uv[i],f1=v[i],f2=u[i];
		}
		int num=0;
		if (!f1){for (int i=e;i;i=last[i]) m[++num]=i;printf("%d",m[num]);for (int i=num-1;i;i--) printf(" %d",m[i]);printf("\nTicket Not Used\n");}
		else{
	    	for (int i=f1;i;i=last[i]) m[++num]=i;
	    	printf("%d",m[num]);
			for (int i=num-1;i;i--) printf(" %d",m[i]);
			num=0;
			for (int i=f2;i;i=Next[i]) printf(" %d",i);
			printf("\n%d\n",f1);
		}
		printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值