C++ B-旅行

题目描述

小z放假了,准备到RRR城市旅行,其中这个城市有N个旅游景点。小z时间有限,只能 在三个旅行景点进行游玩。小明租了辆车,司机很善良,说咱不计路程,只要你一次性缴费足够,我就带你走遍RRR城。
小z很开心,直接就把钱一次性缴足了。然而小z心机很重,他想选择的路程尽量长。
然而司机也很聪明,他每次从一个点走到另外一个点的时候都走最短路径。 你能帮帮小z吗?
需要保证这三个旅行景点一个作为起点,一个作为中转点一个作为终点。(一共三个景点,并且需要保证这三个景点不能重复).

输入描述

本题包含多组输入,第一行输入一个整数t,表示测试数据的组数
每组测试数据第一行输入两个数N,M表示RRR城一共有的旅游景点的数量,以及RRR城中有的路的数量。
接下来M行,每行三个数,a,b,c表示从a景点和b景点之间有一条长为c的路
t<=40 3<=N,M<=1000
1<=a,b<=N
1<=c<=100

输出描述

每组数据输出两行, 每组数据包含一行,输出一个数,表示整条路程的路长。
如果找不到可行解,输出-1.

输入样例

4
7 7
1 2 100
2 3 100
1 4 4
4 5 6
5 6 10
1 6 4
6 7 8
7 3
1 2 1
1 3 1
1 3 2
7 3
1 2 1
3 4 1
5 6 1
8 9
1 2 1
2 3 1
3 4 1
4 1 1
4 5 1
5 6 1
6 7 1
7 8 1
8 5 1

输出样例

422
3
-1
9

解题思路
初学最短路,只会Dijkstra,本来想找模板题做一下的,然后碰上这题,边学边做,一天多才做出来。
解题方法是Dijkstra+链式前向星图(优先队列),用星图存储数据,这还是一个大佬跟我说的,他说很好用,然后特意去学习了一下,具体内容可以看一下这一篇博客
https://blog.csdn.net/LOOKQAQ/article/details/81304637
解题思路是,枚举每个中间点,求出它到各个点的最短路径,再存储最长的两条路径后逐一比较取最大的一组输出。部分问题我在代码里点明。看代码

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int n;
int dist[1005];	//存储最优路径
int head[1005];	//存储第i个结点最后一次出现的位置
int flag[1005];	//存储判断当前节点是否查找过
int cnt=0;

struct Edge{	//to代表指向的节点,w代表权值,next代表上一个源节点出现的位置
	int next,to,w;
}edge[2005];

void add_edge(int u,int v,int w)	//存储
{
	cnt++;
	edge[cnt].w=w;
	edge[cnt].next=head[u];	//将上一个u为源点的位置赋值给next,记录,可以看一下星图搜索的特性,是正输入倒查找的(应该是这个意思)
	edge[cnt].to = v;
	head[u]=cnt;	
}

int Dijkstra(int p)
{
	memset(flag,0,sizeof(flag));
	memset(dist,127,sizeof(dist));	//初始化,memset是按字节初始化的,实现无穷大,具体可以看文末的博客链接
	dist[p]=0;
	priority_queue<pair<int,int>, vector<pair<int, int> >, greater<pair<int, int> > > pq; //优先队列的特性,第一个参数是数据类型,第二个参数是容器类型,第三个参数为比较函数,greater<pair<int,int>>是从大到小排序,less是从小到大。不排序会产生错误答案,会覆盖路径。
	pq.push({0,p});
	int x=0,y=0;
	while(pq.size()){
		pair<int,int> now = pq.top();
		pq.pop();
		int u = now.second;
		if(flag[u]) continue;	
		flag[u]=1;	//如果节点已经找过,则continue
		y = max(y,dist[u]);
		if(y>x) swap(x,y); 		//这个是找到第一大和第二大的路径值,这样写比再写一个循环dist数组要节省时间
		for(int i=head[u];i;i=edge[i].next){
			if(flag[edge[i].to]) continue;
			if(dist[edge[i].to]>dist[u]+edge[i].w){
				dist[edge[i].to]=dist[u]+edge[i].w;
				pq.push({dist[edge[i].to],edge[i].to});
			}
		}
	} 
	if(!y) return 0;
	return x+y;
}
int main()
{
	ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);		//这个是除去c++输入输出缓存
	int t,m,be,en,cost,ans=0;
	cin>>t;
	while(t--){
		cnt=0;
		memset(head,0,sizeof(head));
		cin>>n>>m;
		ans=0;
		for(int i=1;i<=m;i++){
			cin>>be>>en>>cost;
			add_edge(be,en,cost);
			add_edge(en,be,cost);
		}
		for(int i=1;i<=n;i++){
			ans = max(ans,Dijkstra(i));	//遍历每一个节点
		}
		
		if(ans) cout<<ans<<endl;
		else{
			cout<<-1<<endl;
		}
	}
} 

memset 初始化博客推荐
https://blog.csdn.net/Z_sea/article/details/81163447?utm_source=blogxgwz5

priority_queue()
https://blog.csdn.net/qq_41822647/article/details/88899915

大概就是这样的一个代码,我也是边看边学,有些地方也可能理解的不太对,先暂时做个总结,还需加油,太菜了,有问题请指教

题目来源
链接:https://ac.nowcoder.com/acm/problem/14550
来源:牛客网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祖安大龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值