前言
蓝桥杯2021年,填空题(C++)
题目考察了利用dijkstra算法去求最短路径的问题
一、题目描述
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点 之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条 长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
二、思路
从题目可以看出,需要求出最短路径,那么在最短路径问题中平时经常会用到迪杰斯塔拉算法。迪杰斯塔拉算法的主要思想在于一个公式:if(dis[next]>last.n_dis+next.w)dis[next]=last.n_dis+next.w
其中dis[next]表示邻居结点next到初始点的距离,而last.n_dis则表示当前邻居结点之前的那个结点(由该结点才引向了当前邻居结点)到初始点的距离,后者是当前邻居结点之前的那个结点的距离,最终选择一个更小的值来作为路径。
这么说可能比较绕,核心的思想用一句话来概括就是对于每一个要遍历的结点,都会由从该结点寻找所有可能的邻居结点,并计算好这些邻居节点们的最短路径,通过前述公式,然后将这些邻居节点们再装入队列,重复以上操作。
最终答案:10266837
三、具体代码
#include<bits/stdc++.h>
using namespace std;
const long long INF=1e12;
const long long NUM=2030;
struct edge //记录边之间的信息
{
long long start,to,w; //start是该边的起始点,而to是该边的终点,w是距离
edge(long long a,long long b,long long c)
{
start=a;
to=b;
w=c;
}
};
vector<edge> e[NUM]; //用于存储图,这是一个二维数组
struct s_node //记录一个结点的相关信息
{
long long id; //结点编号
long long n_dis; //n_dis,这个结点到起点的距离
s_node(long long b,long long c)
{
id=b;
n_dis=c;
}
bool operator<(const s_node&a)const //重载运算符
{
return n_dis>a.n_dis; //这一步的原因在于priority优先队列默认从大到小排序,如果想要从小到大排序,则需要对运算符重置
}
};
long long n; //总共有n个结点
long long dis[NUM]; //记录所有结点到起点的距离
void dijkstra()
{
long long s=1; //起点是1
bool done[NUM]; //done[i]=true表示到结点i的最短路径已经找到
for(long long i=1;i<=n;i++) //初始化
{
dis[i]=INF;
done[i]=false;
}
dis[1]=0; //起点到自己的距离是0
priority_queue<s_node>q; //优先队列,存结点信息
q.push(s_node(s,0)); //起点进队列
while(!q.empty())
{
s_node temp=q.top();
q.pop();
if(done[temp.id]) //表示当前结点的最短路径已经被处理好了
{
continue;
}
done[temp.id]=true;
for(long long i=0;i<e[temp.id].size();i++) //分别遍历e的所有邻接点
{
edge next=e[temp.id][i]; //表示第i个结点
if(done[next.to]) //如果当前结点已经被处理好了
{
continue;
}
if(dis[next.to]>next.w+temp.n_dis) //算法核心,选择更短的路径
{
dis[next.to]=next.w+temp.n_dis;
}
q.push(s_node(next.to,dis[next.to])); //邻居结点入队列
}
}
}
long long gcd(long long a,long long b)
{
if(a<b)
{
long long temp=a;
a=b;
b=temp;
}
if(b==0)
{
return a;
}
else
{
return gcd(b,a%b);
}
}
int main()
{
n=2021;
for(long long i=1;i<=n;i++)
{
for(long long j=i;j<=n;j++)
{
if(abs(i-j)<=21&&i<j) //避免重复
{
long long w=i*j/gcd(i,j); //两点之间的距离
e[i].push_back(edge(i,j,w));
e[j].push_back(edge(j,i,w));
}
}
}
dijkstra();
cout<<dis[2021]<<endl;
return 0;
}