PTA 旅游大巴

在W市中,旅游大巴是市民从市内去景区A的首选交通工具。旅游大巴分为普通线和快速线两种,线路、速度和价钱都不同。你有一张快速线车票,可以坐一站快速线,而其他时候只能乘坐普通线。假设换乘时间忽略不计,你的任务是找一条去景点A最快的线路。

输入格式:

输入包含多组数据。每组数据第一行为3个整数N,S和E(2≤N≤500,1≤S,E≤100),即旅游大巴中的停靠站总数,起点和终点(即景点A所在站)编号。下一行包含一个整数M(1≤M≤1000),即普通线的路段条数。以下M行每行3个整数X,Y,Z(1≤X,Y≤N,1≤Z≤100),表示可以乘坐普通线在站点X和站点Y之间往返,其中单程需要Z分钟。下一行为快速线的路段条数K(1≤K≤1000),以下K行是这些路段的描述,格式同普通线。所有路段都是双向的,但有可能必须使用快速车票才能到达景点A。保证最优解唯一。

输出格式:

对于每组数据,输出3行。第一行按访问顺序给出经过的各个站点(包括起点和终点),第二行是换乘快速线的车站编号(如果没有快速线车票,输出Ticket Not Used),第三行是总时间。

 输入样例:

4 1 4
4
1 2 2
1 3 3
2 4 4
3 4 5
1
2 4 3

输出样例:

1 2 4
2
5

思路:

 对车票进行枚举 , 先从起始点和终点跑一次最短路:dist[0] 和 dist[1] 。

在迪杰斯特拉中,使用mp[0]  和 mp[1] 分别记录从到这个点的上一个点是谁。

记录初始价值ans为dist[0][ed]  ;(ed为终点,dist[0]为从起始点到别的点的距离;

遍历每张车票:

        将花费分为三段:起点 ->车票a点  , 车票a点-> 车票b点 ,  车票b点->终点;

        若最小价值ans大于使用车票的价值,改变ans,记录zda和zdb为车票的a,b点。

ll zda = -1, zdb = -1;
for(int i = 1;  i<= T ; i ++){
	ll x , y , pr;
	cin >> x >> y >> pr;
	if(dist[0][x] + dist[1][y] + pr < ans){
		ans = dist[0][x] + dist[1][y] + pr;
	    zda = x , zdb = y;
	}
}

最后,如果使用了车票,起点到zda,从zdb到终点就是路径,否则就是从起点到终点的路径。

vector<int>v;
if(~zda){
	ll x = zda , y = zdb;
	while(x){
		v.push_back(x);x = mp[0][x];
	}
	reverse(v.begin(),v.end());
	while(y){
		v.push_back(y);y = mp[1][y];
	}
}else{
	while(sta){
		v.push_back(sta);ed = mp[1][sta];
    }
}

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll int
ll n , m , T;
const int N = 505 , M = 1005;
int sta , ed;
int mp[2][N];
int e[M] , ne[M] , w[M] , dist[2][N] , st[N] , idx , h[N];
void add(int a ,int b, int c){
	ne[idx] = h[a] , e[idx] = b , w[idx] = c , h[a] = idx ++;
}
#define pii pair<int,int>
void bfs(ll ty){
	memset(st,0,sizeof st);
	priority_queue<pii,vector<pii>,greater<pii> > q;
	if(ty == 0)q.push({dist[0][sta],sta});
	if(ty == 1)q.push({dist[1][ed],ed});
	while(!q.empty()){
		auto t = q.top().second;
		q.pop();
		if(st[t])continue;
		st[t] = 1;
		for(int i = h[t] ; ~i ; i = ne[i]){
			int x = e[i];
			if(dist[ty][x] <= dist[ty][t] + w[i])continue;
			dist[ty][x] = dist[ty][t] + w[i];
			mp[ty][x] = t;
			q.push({dist[ty][x],x});
		}
	}
}

int main(){
	ll T = 0;
	while(cin >> n >> sta >> ed){
		if(T ++)cout << endl;
		memset(dist,0x3f ,sizeof dist);
		memset(h , -1 , sizeof h);
		idx = 0;
		cin >> m;
		while(m --){
			ll a , b , c;
			cin >> a >> b >> c;
			add(a,b,c) , add(b,a,c);
		} 
		dist[0][sta] = dist[1][ed] = 0 ;
		mp[0][sta] = mp[1][ed] = 0;
		bfs(0) , bfs(1);
		ll ans = dist[0][ed];
		cin >> T;
		ll zda = -1, zdb = -1;
		for(int i = 1;  i<= T ; i ++){
			ll x , y , pr;
			cin >> x >> y >> pr;
			if(dist[0][x] + dist[1][y] + pr < ans){
				ans = dist[0][x] + dist[1][y] + pr;
				zda = x , zdb = y;
			}
		}
		vector<int>v;
		if(~zda){
			ll x = zda , y = zdb;
			while(x){
				v.push_back(x);x = mp[0][x];
			}
			reverse(v.begin(),v.end());
			while(y){
				v.push_back(y);y = mp[1][y];
			}
		}else{
			while(sta){
				v.push_back(sta);ed = mp[1][sta];
            }
		}
		
		for(int i = 0 ; i < v.size() ; i ++){
			if(i)cout << " " ;cout << v[i];
		}cout << endl;
		if(~zda)cout << zda << endl;
		else cout << "Ticket Not Used\n";
		cout << ans << endl;
	}
}	

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值