【MarsCode题库】M-233 小U的地砖之旅

58 阅读3分钟

M-233.小U的地砖之旅

题目:M-233.小U的地砖之旅

思路

这道题目可以通过建模转换为图论中的“最短路问题”。

以[0, 1, 2, 3, 1, 0]为例,第一个0为地砖Vs,最后一个0为地砖Vt,中间为地砖V1、V2、V3、V4。

有以下路径:(Vs -> V1, V2); (V1 -> V2、V3); (V2 -> V3, V4); (V3 -> V4, Vt); (V4 -> Vt);

图中边的规律是除去倒数第一个点没有后向路径和倒数第二个点只有一条后向路径,其他点都有两条“顺延”的后向路径

我们将题目中给的数组作为求最短路问题连通图中的 G = (V, E) 中的E,然后通过 Dijkstra 算法或者 Floyd 算法求解即可。

代码(Java)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;

public class Main {
    public static int solution(int n, int[] a) {
        // PLEASE DO NOT MODIFY THE FUNCTION SIGNATURE
        // write code here

        // 这道题目可以通过建模转换为图论中的“最短路问题”
        // 以[0, 1, 2, 3, 1, 0]为例,第一个0为地砖Vs,最后一个0为地砖Vt,中间为地砖V1、V2、V3、V4
        // 有以下路径:(Vs -> V1, V2); (V1 -> V2、V3); (V2 -> V3, V4); (V3 -> V4, Vt); (V4 -> Vt);
        // 规律是除去倒数第一个点没有后向路径和倒数第二个点只有一条后向路径,其他点都有两条“顺延”的后向路径
        // 我们将题目中给的数组作为求最短路问题连通图中的 G = (V, E) 中的E,然后通过 Dijkstra 算法或者 Floyd 算法求解即可

        // 此处采用邻接表的方式存储题目中的图
        class Edge {
            int target;d
            int weight;

            Edge(int target, int weight) {
                this.target = target;
                this.weight = weight;
            }
        }

        class WeightedAdjacencyList {

            List<List<Edge>> adjList = new ArrayList<>();

            WeightedAdjacencyList() {
                // 初始化邻接表
                for (int i = 0; i < n; i++) {
                    adjList.add(new ArrayList<>());
                }
                // 添加边
                if (n > 1) {
                    int i;
                    for (i = 0; i < n - 2; i++) {
                        addEdge(i, i + 1, a[i + 1]);
                        addEdge(i, i + 2, a[i + 2]);
                    }
                    addEdge(i, i + 1, a[i + 1]);
                }
            }

            void addEdge(int u, int v, int weight) {
                adjList.get(u).add(new Edge(v, weight));
            }
        }

        WeightedAdjacencyList wAdjList = new WeightedAdjacencyList();

        // 用 Dijkstra 算法寻找源点到目标点的最短路径,此处的 Dijkstra 算法没有保存路径,题目没要求
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        int source = 0; int target = n - 1;
        dist[source] = a[0];

        // 优先对列存储未最优的节点的<节点编号, 当前距离>
        // 这里通过 offer 和 poll 操作间接实现了 final 数组的作用
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(pqItem -> pqItem[1]));
        pq.offer(new int[]{source, a[0]});

        int minDistance = a[0];

        while (!pq.isEmpty()) {
            int[] current = pq.poll();
            int nowVertex = current[0];
            int distance = current[1];

            // 如果当前节点是目标节点,将其赋值但不退出循环
            if (nowVertex == target) {
                minDistance = distance;
            }

            // 遍历当前节点的所有节点
            for (Edge edge : wAdjList.adjList.get(nowVertex)) {
                int vertex = edge.target;
                int weight = edge.weight;

                // 松弛操作
                if (dist[nowVertex] + weight < dist[vertex]) {
                    dist[vertex] = dist[nowVertex] + weight;
                    pq.offer(new int[]{vertex, dist[vertex]});
                }
            }
        }

        return minDistance;

    }

    public static void main(String[] args) {
        System.out.println(solution(5, new int[] { 0, 3, 2, 1, 0 }) == 2);
        System.out.println(solution(4, new int[] { 0, 5, 6, 0 }) == 5);
        System.out.println(solution(6, new int[] { 0, 1, 2, 3, 1, 0 }) == 3);
        System.out.println(solution(1, new int[] { 17 }) == 17);
    }
}

好文参考

图论理论基础 —— 代码随想录

Dijkstra 算法讲解 —— 图码