leetcode
leetcode 2901 ~ 2950
电动车游城市

电动车游城市

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 69 ms, 内存: 16.8 MB


/*
 * 思路:
 * 1. 使用Dijkstra算法求解最短路径问题。
 * 2. 在每个节点计算充电时间和行驶时间的总和。
 * 3. 优化路径以确保总时间最少。
 */
import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    static class Node {
        int city, dist, chargeTime;
        Node(int city, int dist, int chargeTime) {
            this.city = city;
            this.dist = dist;
            this.chargeTime = chargeTime;
        }
    }

    public int minTime(int[][] paths, int cnt, int start, int end, int[] charge) {
        int n = charge.length;
        List<List<int[]>> graph = Arrays.stream(new List[n]).map(ArrayList::new).collect(Collectors.toList());
        Arrays.stream(paths).forEach(path -> {
            graph.get(path[0]).add(new int[]{path[1], path[2]});
            graph.get(path[1]).add(new int[]{path[0], path[2]});
        });

        PriorityQueue<Node> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a.dist + a.chargeTime));
        pq.add(new Node(start, 0, 0));
        int[][] minTime = new int[n][cnt + 1];
        Arrays.stream(minTime).forEach(row -> Arrays.fill(row, Integer.MAX_VALUE));
        minTime[start][0] = 0;

        while (!pq.isEmpty()) {
            Node node = pq.poll();
            int city = node.city, dist = node.dist, chargeTime = node.chargeTime;
            if (city == end) return dist + chargeTime;
            graph.get(city).forEach(neighbor -> {
                int nextCity = neighbor[0], travelDist = neighbor[1];
                for (int newCharge = 0; newCharge + travelDist <= cnt; newCharge++) {
                    int totalChargeTime = newCharge * charge[city];
                    int totalTime = dist + travelDist + chargeTime + totalChargeTime;
                    if (totalTime < minTime[nextCity][newCharge + travelDist]) {
                        minTime[nextCity][newCharge + travelDist] = totalTime;
                        pq.add(new Node(nextCity, dist + travelDist, chargeTime + totalChargeTime));
                    }
                }
            });
        }

        return -1;
    }
}

解释

方法:

这个题解使用了带有优先队列(最小堆)的Dijkstra算法变种,结合状态转移来解决问题。每个状态由当前城市和车上的电量决定,形成一个状态空间。dist数组存储到达每个状态的最小时间。从起点开始,不断探索出发到其他城市的可能性,同时考虑在当前城市充电的可能性。当从优先队列中取出的状态的时间大于已记录的最小时间,则跳过该状态。算法结束的条件是当访问到终点城市时,队列中的第一个合法状态即为最小时间。此外,算法还考虑了每次充电的时间成本,并在每个城市尝试充电后再行驶到下一个城市,以及直接从当前电量出发到能达到的下一个城市。

时间复杂度:

O(n^2 * cnt * log(n*cnt))

空间复杂度:

O(n * cnt)

代码细节讲解

🦆
为何在进行充电决策时,仅考虑增加1单位电量而不是多个单位电量,这样的策略是否最优?
在设计电动车游城市的算法中,每次仅考虑增加1单位电量而非多个单位的原因有两个:首先,这种策略简化了状态转移的复杂性。在每个城市充电时只考虑增加1单位电量,可以使状态空间和决策过程更加清晰和易于管理。其次,这种方法可以保证在任何时刻都能找到达到某状态的最小时间。如果一次充多个单位电量,虽然可能在某些情况下更快,但会使问题的状态空间剧增,增加了计算的复杂度。此外,这种逐步充电的策略可以在每一步都重新评估是否继续充电或驶向下一个城市,这样做提供了更好的灵活性和可能达到更优的总体策略。因此,虽然看似增加了步骤,实际上此策略有助于维护算法的效率和实现全局最优解。

相关问题