dijkstra应用-TT 的旅行日记

题意

众所周知,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 前往喵星机场花费的总时间。
本题不忽略多余的空格和制表符,且每一组答案间要输出一个换行

思路

该题显然是需要求一条最短路(时间最短),因为没有负边,所以可以用dij,但是这里不同的是路线中可以用一条商业线,因为商业线数固定,所以可以枚举每一条商业线(u,v),计算起点到u的最短路+v到终点的最短路+该商业线花费的时间,即以起点为源点求最短路,得到dis1数组,以终点为源点求最短路,得到dis2数组,又因为线路是双向的,所以枚举商业线(u,v,w),取min{dis1[u]+dis2[v]+w,dis1[v]+dis2[u]+w},最终在与不走商业线的答案取min.

总结

该题是典型的dij求最短路,区别在于有一条商业线,进行枚举就可用dij

反思

该题需要注意输出格式

代码

//dij堆优化   邻接表 
//不能解决权值为负问题 
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
# define inf 100000000
int dis1[510],dis2[510];bool flag[510];int np1[510],np2[510];
int n,s,e;
priority_queue<pair<int,int> >q;//距离   点 
vector<pair<int,int> >ve[510];// 点  权重 
void dijkstra(int s,int dis[510],int np[510])
{
	while(q.size()) q.pop();
	memset(flag,0,sizeof(flag));
	for(int i=1;i<=n;i++)
	np[i]=s;
	for(int i=1;i<=n;i++) dis[i]=inf;//最长路-inf 
	dis[s]=0;np[s]=-1;q.push(make_pair(0,s));
	while(q.size())
	{
		int x=q.top().second;//int v=q.top().frist //最长路加的 //最长路也不能解决正环(循环)问题 
		q.pop();
		if(flag[x])continue;//说明每个点dis[i]选出后就不会确定了,没有负权情况,更没有负环情况
		//最长路这里需要改变 if(v<dis[x])continue;
		flag[x]=1;//最长路这里就不要了 
		for(int i=0;i<ve[x].size();i++) 
		{
			if(dis[ve[x][i].first]>dis[x]+ve[x][i].second)//最长路< 
			 dis[ve[x][i].first]=dis[x]+ve[x][i].second,np[ve[x][i].first]=x,
			 q.push(make_pair(-dis[ve[x][i].first],ve[x][i].first));//最长路改成最大堆 
		}		
	}	
}
void print(int s)
{
	if(np1[s]==-1)
	{cout<<s;return;
	}
	print(np1[s]);
	cout<<" "<<s;
}
void pprint(int s)
{  if(s==e) cout<<s;
   else cout<<s<<" ";
   if(s==e)
   return;
	pprint(np2[s]);
}
int main()
{   int kkk=0;//freopen("in.txt","r",stdin);
	while(scanf("%d%d%d",&n,&s,&e)!=EOF)
	{   if(kkk!=0)cout<<endl;kkk++;
    	for(int i=1;i<=n;i++)
	   {
		 while(ve[i].size()) ve[i].pop_back();
	   }
	   int m;scanf("%d",&m);
	   for(int i=1;i<=m;i++)
	   {
	   	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	   	ve[a].push_back(make_pair(b,c));
	   	ve[b].push_back(make_pair(a,c));
	   } dijkstra(s,dis1,np1);dijkstra(e,dis2,np2);//dis1[e]就是没有商业的
	   //dis1[u] dis1[v]   //dis2[v]  dis2[u]
	   int k;scanf("%d",&k);int x=s,y=e,t=dis1[e];bool flag=0;
	   for(int i=1;i<=k;i++)
	   {
	   	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	   	int val=min(dis1[a]+dis2[b]+c,dis1[b]+dis2[a]+c);
	   	if(t>val)
	   	{   if(dis1[a]+dis2[b]+c>dis1[b]+dis2[a]+c)
	   	   	t=val,x=b,y=a;
	   	   	else t=val,x=a,y=b;flag=1;
		   }
	   }   
	   if(!flag)
	      {
	      	print(e);cout<<endl;cout<<"Ticket Not Used"<<endl;cout<<t<<endl;
		  }
		  else 
		  {
		  	print(x);cout<<" ";pprint(y);cout<<endl;cout<<x<<endl;cout<<t<<endl;
		  }	   
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值