题目描述:
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由2021 个结点组成,依次编号1 至2021。
对于两个不同的结点a, b,如果a 和b 的差的绝对值大于21,则两个结点之间没有边相连;
如果a 和b 的差的绝对值小于等于21,则两个点之间有一条长度为a 和b 的最小公倍数的无向边相连。
例如:结点1 和结点23 之间没有边相连;结点3 和结点24 之间有一条无向边,长度为24;
结点15 和结点25 之间有一条无向边,长度为75。
请计算,结点1 和结点2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
思路:
本题考最短路径和最小公倍数。
最小公倍数由两数之积除以他们的最大公约数得到
采用Dijkstra算法,每次加入一个点,更新最短路径,直至得到起点到终点的最小值。
完整代码:
public class Main {
static int inf = Integer.MAX_VALUE; // 定义没有路径时的距离表示
public static void main(String[] args) {
int[][] node = new int[2022][2022]; // 用二维数组存放两点之间的距离
for (int i=1;i<=2021;i++){
for (int j=1;j<=2021;j++){
if (i==j) // 到自己的距离为0
node[i][j] = 0;
else if (Math.abs(i-j)>21) // 两点之差大于21时,没有路径
node[i][j] = inf;
else
node[i][j] = (i*j)/gcd(i,j); // 距离小于等于21,距离是最小公倍数
}
}
int[] dijst = new int[2022]; // 表示dijst[i]表示1到i点的距离
int[] visit = new int[2022]; // visit[i]=1时,表示i点已加入点集
for (int i=1;i<=2021;i++){
dijst[i] = node[1][i]; // 初始化1到各点之间的距离
}
for (int i=1;i<2021;i++){
int min = inf, index = 0;
for (int j=2;j<=2021;j++){
if (visit[j]==0&&dijst[j]<min){
min = dijst[j]; // 每次选择最短距离
index = j; // 保存点的索引
}
}
visit[index] = 1; // 使vistt数组对应的索引为1
for (int k=1;k<=2021;k++){ // 每加入一个点,就将1到所有点最小距离更新
if (node[index][k]<inf){ // 当辅助点之间有路径时才做修改
if (dijst[k]>dijst[index]+node[index][k]) // 若1到k之间的距离小于1到辅助点,再到k的距离
dijst[k]=dijst[index]+node[index][k]; // 就更新1到k的最短距离
}
}
}
System.out.println(dijst[2021]);
}
private static int gcd(int a, int b){ // 求最大公约数的函数
return b==0?a:gcd(b,a%b);
}
}