拿出一道第十二届蓝桥杯JavaB组省赛的E题来实现代码
试题 E: 路径
本题总分:10 分
【问题描述】
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图
中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点
之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条
长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无
向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Graph {
public static void main(String[] args) {
List<Vertex> list = new ArrayList<>();
for (int i = 1; i < 2022; i++) {
list.add(new Vertex(i));
}
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.size(); j++) {
if(Math.abs(i-j)<=21 && i != j){
int lcm = lcm(list.get(i).value,list.get(j).value);
list.get(i).edges.add(new Edge(lcm,list.get(j)));
}
}
}
dfs(list.get(0));
System.out.println(list.get(2020).dist);
}
//求最大公约数
public static int gcd(int a,int b){
if(b == 0){
return a;
}
return gcd(b,a%b);
}
//求最小公倍数
public static int lcm(int a,int b){
return a * b / gcd(a,b);
}
//dfs深度优先搜索遍历
public static void dfs(Vertex vertex){
Queue<Vertex> queue = new LinkedList<>();
vertex.dist = 0;
//每个节点只遍历一次它的边
vertex.isVisit = true;
queue.offer(vertex);
while (!queue.isEmpty()){
//获取队列第一个元素,并遍历它的边
Vertex poll = queue.poll();
for (Edge edge : poll.edges) {
int dist = poll.dist + edge.weight;
//从poll节点各个边到达的其它节点,如果距离更短了就更新
if(dist < edge.linked.dist){
edge.linked.dist = dist;
}
//判断节点的关联边是否遍历过,没有就进队列
if(!edge.linked.isVisit){
queue.offer(edge.linked);
edge.linked.isVisit = true;
}
}
}
}
}
//节点类
class Vertex{
int value;
List<Edge> edges = new ArrayList<>();
int dist = Integer.MAX_VALUE;
Boolean isVisit = false;
public Vertex(int value) {
this.value = value;
}
}
//边类
class Edge{
int weight;
Vertex linked;
public Edge(int weight, Vertex linked) {
this.weight = weight;
this.linked = linked;
}
}