题目描述
小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
来源:牛客网