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

题目思路:

一.跑2k遍最短路,去遍历每条快速线的费用,取最小

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e4+5;
const int inf=0x3f3f3f3f3f3f3f3f;
struct node{
	int fr,v,next,top;
	int val;
}arr[N];
int cnt,n,s,e;
int head[N],vis[N],dis[N];
int mix[505][505];
unordered_map<int,int>mp[N];
void add(int u,int v,int val){
	arr[++cnt]={u,v,head[u],0,val};
	arr[head[u]].top=cnt;
	head[u]=cnt;
}
void dee(int now){
	int up=arr[now].top;
	int down=arr[now].next;
	if(up==0)head[arr[now].fr]=down;
	else arr[up].next=down;

	if(down>0)arr[down].top=up;
}
int ans[N];
void inti(){
	cnt=0;
	memset(head,-1,sizeof head);
	memset(mix,0x3f,sizeof mix);
	for(int i=0;i<=n;i++){
		mp[i].clear();
	}
}
void dijkstra(int x){
	memset(vis,0,sizeof vis);
	memset(dis,0x3f,sizeof dis);
	memset(ans,0,sizeof ans);
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
	q.push({0,x});
	dis[x]=0;
	while(!q.empty()){
		pair<int,int>index=q.top();
		q.pop();
		if(vis[index.second])continue;
		vis[index.second]=1;
		for(int i=head[index.second];~i;i=arr[i].next){
			int v=arr[i].v;
			if(dis[v]>index.first+arr[i].val){
				dis[v]=index.first+arr[i].val;
				ans[v]=index.second;
				q.push({dis[v],v});
			}
		}
	}
}
void solve(){
	int f=0;
	while(cin>>n>>s>>e){
		if(f)cout<<endl;
		f=1;
		inti();
		int m;cin>>m;
		while(m--){
			int a,b,c;cin>>a>>b>>c;
			mix[a][b]=min(mix[a][b],c);
			mix[b][a]=min(mix[b][a],c);
			add(a,b,c);
			add(b,a,c);
		}
		int fk;cin>>fk;
		int minn=inf;
		vector<int>last;
		int ck=-1;
		while(fk--){
			int F=0;
			int a,b,c;cin>>a>>b>>c;
			if(mix[a][b]>c){
				add(a,b,c);
				add(b,a,c);
				dijkstra(s);
				dee(cnt);
				dee(cnt-1);
			}else{
				F=1;
				dijkstra(s);
			}
			if(dis[e]<minn){
				int p=e;
				last.clear();
				last.push_back(p);
				while(ans[p]!=0){
					last.push_back(ans[p]);
					p=ans[p];
				}
				minn=dis[e];
				if(F==0){
					mp[fk][a]++;
					mp[fk][b]++;
				}
				ck=fk;
			}
		}
		int ls=-1;
		for(int i=last.size()-1;i>=0;i--){
			if(i-1>=0&&mp[ck].count(last[i])&&mp[ck].count(last[i-1])){
				ls=last[i];
			}
			cout<<last[i]<<(i==0?"\n":" ");
		}
		if(ls!=-1){
			cout<<ls<<endl;
		}else cout<<"Ticket Not Used"<<endl;
		cout<<minn<<endl;
	}
}
signed main(){
//	IOS;
	solve();
	return 0;
}

二.跑两遍最短路。

去比较每条快速线被使用的费用是否会比不用快速线的费用要短。

不用快速线的费用为起点---->终点的费用。

用快速线的费用则为起点------>快速线起点的费用加上快速线的费用加上快速线------>终点的费用。

两者费用进行比较,短了则更新需要打印的路径。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int inf=0x3f3f3f3f3f3f3f3f;
const int N=1e5+5;
int n,s,e,cnt,m;
int vis[N],head[N],d[N],d1[N],d2[N]; 
int ans1[N],ans2[N];
vector<int>v,sumlc;
struct node{
	int v,w,next;
}bian[N];
struct cmp{
	bool operator()(int x,int y){
		return d[x]>d[y];
	}
};
void init(){
	memset(head,-1,sizeof head);
	memset(ans1,0,sizeof ans1);
	memset(ans2,0,sizeof ans2);
	cnt=1;
}
void add(int u,int v,int w){
	bian[cnt].v=v;
	bian[cnt].w=w;
	bian[cnt].next=head[u];
	head[u]=cnt++; 
}
void djst(int x){
	memset(d,0x3f,sizeof d);
	memset(vis,0,sizeof vis);
	priority_queue<int,vector<int>,cmp>q;
	q.push(x);
	d[x]=0;
	while(!q.empty()){
		int k=q.top();
		q.pop();
		if(vis[k])continue;
		vis[k]=1;
		for(int i=head[k];i!=-1;i=bian[i].next){
			int v=bian[i].v;
			int w=bian[i].w;
			if(d[v]>d[k]+w){
				d[v]=d[k]+w;
				ans1[v]=k;
				q.push(v);
			}
		}
	}
}
void djst1(int x){
	memset(d,0x3f,sizeof d);
	memset(vis,0,sizeof vis);
	priority_queue<int,vector<int>,cmp>q;
	q.push(x);
	d[x]=0;
	while(!q.empty()){
		int k=q.top();
		q.pop();
		if(vis[k])continue;
		vis[k]=1;
		for(int i=head[k];i!=-1;i=bian[i].next){
			int v=bian[i].v;
			int w=bian[i].w;
			if(d[v]>d[k]+w){
				d[v]=d[k]+w;
				q.push(v);
				ans2[v]=k;
			}
		}
	}
}
void cmp(){
	v.clear();
	int p=e;
	v.push_back(e);
	while(ans1[p]!=0){
		v.push_back(ans1[p]);
		p=ans1[p];
	} 
	sumlc=v;
}
//s->x->y->e
void cmp1(int x,int y){
	v.clear();
	int p=y;
	v.push_back(p);
	while(ans2[p]!=0){
		v.push_back(ans2[p]);
		p=ans2[p];
	}
	v.push_back(x);
	p=x;
	while(ans1[p]!=0){
		v.push_back(ans1[p]);
		p=ans1[p];
	}
	sumlc=v;
}
void solve(){
	int flag=0;
	while(cin>>n>>s>>e){
		if(flag)cout<<endl;
		flag=1;
		init();
		cin>>m;
		for(int i=0;i<m;i++){
			int x,y,z;
			cin>>x>>y>>z;
			add(x,y,z);add(y,x,z);
		}
		djst(s);
		int minn=d[e];
		for(int i=1;i<=n;i++){
			d1[i]=d[i];
		}
		cmp();
		djst1(e);
		for(int i=1;i<=n;i++){
			d2[i]=d[i];
		}
		int kk;
		cin>>kk;
		int f=0;
		for(int i=0;i<kk;i++){
			int x,y,z;
			cin>>x>>y>>z;
			if(d1[x]+z+d2[y]<minn){
				minn=d1[x]+z+d2[y];f=x;
				cmp1(x,y);
			}else if(d1[y]+z+d2[x]<minn){
				minn=d1[y]+z+d2[x];f=y;
				cmp1(y,x);
			}
		}
		for(int i=sumlc.size()-1;i>=0;i--){
			cout<<sumlc[i];
			if(i!=0)cout<<" ";
			else cout<<endl;
		}
		if(f==0)cout<<"Ticket Not Used"<<endl;
		else cout<<f<<endl;
		cout<<minn<<endl;
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//	int _;
//	cin>>_;
//	while(_--){
		solve();
//	}
	return 0;
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值