B - TT 的旅行日记(Week7作业)

题目

众所周知,TT 有一只魔法猫。
今天他在 B 站上开启了一次旅行直播,记录他与魔法猫在喵星旅游时的奇遇。 TT
从家里出发,准备乘坐猫猫快线前往喵星机场。猫猫快线分为经济线和商业线两种,它们的速度与价钱都不同。当然啦,商业线要比经济线贵,TT
平常只能坐经济线,但是今天 TT 的魔法猫变出了一张商业线车票,可以坐一站商业线。假设 TT 换乘的时间忽略不计,请你帮 TT
找到一条去喵星机场最快的线路,不然就要误机了!

输入

输入包含多组数据。每组数据第一行为 3 个整数 N, S 和 E (2 ≤ N ≤ 500, 1 ≤ S, E ≤ 100),即猫猫快线中的车站总数,起点和终点(即喵星机场所在站)编号。
下一行包含一个整数 M (1 ≤ M ≤ 1000),即经济线的路段条数。
接下来有 M 行,每行 3 个整数 X, Y, Z (1 ≤ X, Y ≤ N, 1 ≤ Z ≤ 100),表示 TT 可以乘坐经济线在车站 X 和车站 Y 之间往返,其中单程需要 Z 分钟。
下一行为商业线的路段条数 K (1 ≤ K ≤ 1000)。
接下来 K 行是商业线路段的描述,格式同经济线。
所有路段都是双向的,但有可能必须使用商业车票才能到达机场。保证最优解唯一。

输出

对于每组数据,输出3行。第一行按访问顺序给出 TT 经过的各个车站(包括起点和终点),第二行是 TT 换乘商业线的车站编号(如果没有使用商业线车票,输出"Ticket Not Used",不含引号),第三行是 TT 前往喵星机场花费的总时间。
本题不忽略多余的空格和制表符,且每一组答案间要输出一个换行

输入样例

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

题目思路

——处理经济线
·思想:Dijkstra方法分别从起点与终点遍历一遍,记录下单源最短路(无负权边)
·实现:以s为起点,dis[i]记录起点到i的最短距离,初始化dis[]为inf,将起点放入最小堆中,取出最小堆的根,对dis[]数组更新,若与起点s相连的邻接点y之间的边被松弛,即dis[y]>dis[x]+w,则更新dis[y]并把y放入最小堆中。
· 时间复杂度:O((n+m)logn)
·分别从起点和终点求单源最短路,fdis和sdis

——加入商业线
·枚举商业路线
·将当前商业路线代入算出时间
	·若当前时间小于记录的值,更新ans;
	·否则枚举下一个商业路线。

实现细节(踩到的坑)

1、多组数据!!
2、没有考虑到这是一个无向图,存在3->4也必然存在4->3,且有可能是答案
3、有一个地方因为代码比较像直接复制过去,导致一些数据没有改,导致一直wa
4、输出的格式,这个题目输出格式比较严格,一定要仔细读题
5、尽量一口气写完中间不要随意换,导致前后驴头不对马嘴,容易出错。
6、vector的v.insert(v.begin(),x),是指放在前面。

代码实现

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<vector> 
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN=2010;
struct node{
	int to,nex,w;
}edges[MAXN];
int n,s,e,m,k,num,ans=inf;
int comx,comy;
int Head[MAXN];
bool vis[MAXN];
int fdis[MAXN],fink[MAXN],sdis[MAXN],sink[MAXN];
priority_queue<pair<int,int> > q;
vector<int> p;
void dijkstra(int s,int *dis,int *ink)
{
	for(int i=0;i<=n;i++) 
	{
		dis[i]=inf;
		vis[i]=false; 
	}
	while(q.size()) q.pop();
	q.push(make_pair(0,s));dis[s]=0;
	while(q.size())
	{
		int temp=q.top().second;
		q.pop();
		if(vis[temp]) continue;
		vis[temp]=true;
		for(int i=Head[temp];i;i=edges[i].nex)
		{
			int y=edges[i].to;int wgt=edges[i].w;
			if(dis[y]> dis[temp]+wgt)
			{
				dis[y]=dis[temp]+wgt;
				ink[y]=temp;
				q.push(make_pair(-dis[y],y));
			}
		}	
	}	
}
void add(int x,int y,int z)
{
	num++; 
	edges[num].to=y;
	edges[num].nex=Head[x];
	edges[num].w=z;
	Head[x]=num;
}
void init()
{
	for(int i=0;i<=n;i++)
		Head[i]=-1;
	num=0;ans=inf;
	p.clear();
	memset(fink,0,sizeof(fink));
	memset(sink,0,sizeof(sink));
}
int main()
{
	int judge=0;
	while(scanf("%d%d%d",&n,&s,&e)!=EOF)
	{
		if(judge==0) judge++;
		else putchar('\n');
		
		init();
        
		scanf("%d",&m);
		for(int i=0;i<m;i++)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add(x,y,z);
			add(y,x,z);
		}
		dijkstra(s,fdis,fink);
		dijkstra(e,sdis,sink);
		
		scanf("%d",&k);
		for(int i=0;i<k;i++)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			if(ans>fdis[x]+sdis[y]+z)
			{
				ans=fdis[x]+sdis[y]+z;
				comx=x;comy=y;
			}
			if(ans>fdis[y]+sdis[x]+z)
			{
				ans=fdis[y]+sdis[x]+z;
				comx=y;comy=x;
			}
		}
		
		if(ans>fdis[e]) 
		{
			for(int st=e;st!=s;st=fink[st])
				p.push_back(st);
			p.push_back(s);
			
			for(int i=p.size()-1;i>0;i--)
				printf("%d ",p[i]);
			printf("%d\n",p[0]);
			printf("Ticket Not Used\n");
			printf("%d\n",fdis[e]);
		}
		else
		{
			for(int st=comx;st!=s;st=fink[st])
				p.push_back(st);
			p.push_back(s);
			for(int st=comy;st!=e;st=sink[st])
				p.insert(p.begin(),st);
			p.insert(p.begin(),e);
			
			for(int i=p.size()-1;i>0;i--)
				printf("%d ",p[i]);
			printf("%d\n",p[0]);
			
			printf("%d\n",comx);
			printf("%d\n",ans);
		} 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值