题目
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点 之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条 长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题
思路
题目意思已经很明确了,使用最短路径来解决问题,最短路径有专门的算法,我在这里使用的Dijkstra算法。这道题不只考查最短路径,还涉及到 最小公倍数的查找,在这里使用递归对其进行判断。对数组初始化时,一定要选择一个较大的数,不然比较那里就会出现问题。因为1到2021的最短路径是一个很大的数,注意,注意,注意!
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define inf 1000000000
#define N 3000
#define n 2021
int a[N][N];
int gkd(int b,int z)
{
if(z==0)
return b;
else
return gkd(z,b%z);
}
void DJ()(Dijkstra算法过程)
{
int dist[N],visit[N],i,j,k,min,c;
for(i=1;i<=n;i++)
{
dist[i]=a[1][i];
}
for(i=1;i<=n;i++)
{
visit[i]=0;
}
for(i=1;i<=n;i++)
{
min=inf;
for(j=1;j<=n;j++)
{
if(visit[j]==0&&dist[j]<min)
{
min=dist[j];
k=j;
}
}
visit[k]=1;
for(c=1;c<=n;c++)
{
if(a[k][c]<inf)
{
if(dist[c]>dist[k]+a[k][c])
{
dist[c]=dist[k]+a[k][c];
}
}
}
}
printf("%d",dist[n]);
}
int main()
{
int i,j;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(i==j)
a[i][j]=0;
else
a[i][j]=inf;
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(i!=j)
{
if(abs(i-j)<=21)
{
a[i][j]=i*j/gkd(i,j);(求最小公倍数)
a[j][i]=i*j/gkd(i,j);
}
}
}
}
DJ();
return 0;
}