题目解析 82题 理想火车站定位| 豆包MarsCode AI刷题

131 阅读3分钟

题目回顾:

问题描述

小F是A市的市长,正在计划在A市新建一个火车站以方便市民的日常出行。市区内的街道布局十分规整,形成网格状。从一个位置[x1, y1]到另一个位置[x2, y2]的距离计算方法为 |x1 - x2| + |y1 - y2|,即曼哈顿距离。

在初步考察后,市政府列出了M个可能的火车站建设点。为了使得市民到火车站的总旅行时间最短,小F希望选出一个最优位置作为火车站的地址。

请你帮助小F计算出哪一个位置最适合建设新火车站。

  • N: 市民的总人数。
  • M: 可建设火车站的备选位置数。
  • citizens: 一个列表,每个元素是一个元组 [x_i, y_i],表示第 i 位市民的居住位置。
  • locations: 一个列表,每个元素是一个元组 [p_i, q_i],表示第 i 个备选的火车站位置。

如果有多个火车站最优,那么选择第一次出现的那个。

测试样例

样例1:

输入:n = 4,m = 3,citizens = [[-1, -1], [-1, 1], [1, -1], [1, 1]],locations = [[3, 2], [1, 0], [0, 0]]
输出:[1, 0]

样例2:

输入:n = 2,m = 2,citizens = [[0, 0], [0, 4]],locations = [[0, 2], [0, 3]]
输出:[0, 2]

样例3:

输入:n = 3,m = 1,citizens = [[10, 10], [20, 20], [30, 30]],locations = [[15, 15]]
输出:[15, 15]

样例4:

输入:n = 5,m = 3,citizens = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]],locations = [[4, 5], [6, 7], [8, 9]]
输出:[4, 5]

题目分析:

要解决这个问题,我们需要找到一个最佳的火车站位置,使得所有市民到这个位置的总旅行时间(即总曼哈顿距离)最小。这里的关键在于如何有效地计算每个备选位置的总旅行时间,并从中挑选出最小值对应的地点。

   暴力搜索法

  1. 遍历所有备选位置:对于每一个可能的火车站位置,计算所有市民到达该位置的总旅行时间。
  2. 计算总旅行时间:对于每一个备选位置,使用曼哈顿距离公式∣x1​−x2​∣+∣y1​−y2​∣ 计算每个市民到该位置的距离,然后将这些距离相加得到总旅行时间。
  3. 比较并选择最优位置:记录下每个备选位置的总旅行时间,最后选择总旅行时间最小的位置。如果存在多个总旅行时间相同的备选位置,则选择第一次出现的那个。

解题步骤:

1.定义曼哈顿距离计算函数

曼哈顿距离是指两个点在标准坐标系上的绝对轴距之和,公式为:

                                                 distance=∣x1​−x2​∣+∣y1​−y2​∣

定义一个函数 manhattan_distance 来计算两个点之间的曼哈顿距离。

2.初始化最优位置和最小总旅行时间

  • 初始化一个变量 best_locationNone,用于记录当前最优位置。
  • 初始化一个变量 min_total_distance 为正无穷大 float('inf'),用于记录当前最小的总旅行时间。

3.遍历所有备选位置

  • 对于每个备选位置,计算所有市民到该位置的总旅行时间。
  • 如果当前总旅行时间小于已知的最小总旅行时间,则更新 best_locationmin_total_distance

4.返回最优位置

  • 遍历完成后,返回 best_location

以下是解题代码:

//定义距离函数
function manhattanDistance(p1, p2) {
  // 计算两个点之间的曼哈顿距离
  return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1]);
}

function solution(n, m, citizens, locations) {
  let bestLocation = null;
  let minTotalDistance = Infinity;

  for (let location of locations) {
    let totalDistance = 0;
    for (let citizen of citizens) {
      totalDistance += manhattanDistance(citizen, location);
    }
    
    if (totalDistance < minTotalDistance) {
      minTotalDistance = totalDistance;
      bestLocation = location;
    }
  }

  return bestLocation;
}

function main() {
  // 测试用例
  const citizens1 = [[-1, -1], [-1, 1], [1, -1], [1, 1]];
  const locations1 = [[3, 2], [1, 0], [0, 0]];
  console.log(solution(4, 3, citizens1, locations1).toString() === [1, 0].toString()); // 应输出 true
}

main();

动态规划:

动态规划思路

动态规划的核心思想是将问题分解成子问题,并通过存储子问题的解来避免重复计算。对于这道题,我们可以考虑以下几点:

  1. 状态定义:我们需要一个状态来表示当前最优位置及其对应的总旅行时间。
  2. 状态转移:通过逐步计算每个备选位置的总旅行时间,并更新最优位置。
  3. 初始化和边界条件:初始状态下,最优位置可以设为第一个备选位置,总旅行时间为所有市民到该位置的总旅行时间。

本题具体分析:

我们可以定义一个二维数组 dp,其中 dp[i][j] 表示前 i 个市民到第 j 个备选位置的总旅行时间。但是,考虑到我们只需要找到一个最优位置,而不是所有子问题的解,我们可以简化这个过程,使用一个一维数组来存储当前的最优位置和总旅行时间。

function manhattanDistance(p1, p2) {
    // 计算两个点之间的曼哈顿距离
    return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1]);
}

function solution(n, m, citizens, locations) {
    // 初始化最优位置和最小总旅行时间
    let bestLocation = null;
    let minTotalDistance = Infinity;
    
    // 预计算每个市民到每个备选位置的距离
    let distances = citizens.map(citizen => 
        locations.map(location => manhattanDistance(citizen, location))
    );
    
    // 动态规划部分
    for (let j = 0; j < m; j++) {
        let totalDistance = 0;
        for (let i = 0; i < n; i++) {
            totalDistance += distances[i][j];
        }
        
        if (totalDistance < minTotalDistance) {
            minTotalDistance = totalDistance;
            bestLocation = locations[j];
        }
    }
    
    return bestLocation;
}

if (typeof module !== 'undefined' && require.main === module) {
    // 测试用例
    const citizens1 = [[-1, -1], [-1, 1], [1, -1], [1, 1]];
    const locations1 = [[3, 2], [1, 0], [0, 0]];
    console.log(JSON.stringify(solution(4, 3, citizens1, locations1)) === JSON.stringify([1, 0]));  // 应输出 true
}

好的,以上就是本道题的解答和思路

这里提供两个方法 分别是暴力搜索和动态规划