一、理想火车站定位问题
1、问题描述
小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个备选的火车站位置。
如果有多个火车站最优,那么选择第一次出现的那个。
2、测试样例
样例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]
样例5:
输入:
n = 6,m = 2,citizens = [[10, 10], [20, 20], [30, 30], [40, 40], [50, 50], [60, 60]],locations = [[35, 35], [45, 45]]
输出:[35, 35]
二、问题分析
1、解题思路
这个问题要求我们找出一个最优的火车站位置,使得所有市民到火车站的总旅行时间(曼哈顿距离)最短。解题的关键在于理解曼哈顿距离的计算方式和如何通过比较不同火车站位置来找出最优解。
2、解题步骤
- 初始化变量:我们需要一个变量来存储当前找到的最小总距离( minTotalDistance ),以及一个数组来存储最优火车站的位置( bestLocation )。
- 遍历备选位置:对于每个备选的火车站位置,我们计算所有市民到这个位置的总旅行时间。
- 计算总旅行时间:对于每个市民,我们使用曼哈顿距离公式计算他们到当前备选火车站位置的距离,并将这些距离累加起来。
- 更新最优位置:如果当前备选位置的总旅行时间小于我们之前记录的最小总距离,我们就更新最小总距离和最优位置。
- 返回结果:遍历完所有备选位置后,我们返回最优位置。
三、代码实现
public class Main {
public static int[] solution(int n, int m, int[][] citizens, int[][] locations) {
int minTotalDistance = Integer.MAX_VALUE;
int[] bestLocation = new int[]{-1, -1};
// 遍历每个备选火车站位置
for (int[] location : locations) {
int totalDistance = 0;
// 计算所有市民到当前备选位置的总旅行时间
for (int[] citizen : citizens) {
totalDistance += Math.abs(citizen[0] - location[0]) + Math.abs(citizen[1] - location[1]);
}
// 更新最优位置
if (totalDistance < minTotalDistance) {
minTotalDistance = totalDistance;
bestLocation = location;
}
}
return bestLocation;
}
public static boolean arrayEqual(int[] a, int[] b) {
if (a.length != b.length) {
return false;
}
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
public static void main(String[] args) {
int[][] citizens1 = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
int[][] locations1 = {{3, 2}, {1, 0}, {0, 0}};
int[] result = solution(4, 3, citizens1, locations1);
int[] expected = {1, 0};
System.out.println(arrayEqual(result, expected));
}
}
四、复杂度分析
1、时间复杂度分析
假设N是市民的总人数,M是备选火车站的位置数,则该问题代码的时间复杂度为O(N*M)。这是因为我们需要对每个备选位置计算所有市民的旅行时间,而每个市民的旅行时间计算是O(1)。
2、空间复杂度分析
该问题代码的空间复杂度为O(1),这是因为我只使用了常数个额外的变量来存储最小总距离和最优位置,不依赖于输入规模。
五、总结
1、知识点总结
该问题涉及到的知识点主要有以下几个方面:
- 曼哈顿距离:在网格状布局中,从一个点到另一个点的距离可以通过绝对坐标差的和来计算。
- 双重循环:在这个问题中,我们需要对备选位置和市民的位置进行双重遍历。
- 条件判断:通过比较总旅行时间来更新最优位置。
- 数组操作:在Java中,使用数组来存储和比较位置信息。
2、优化点
在这个问题中,我没有使用任何特殊的数据结构或算法来优化性能,因为问题本身的性质决定了我们需要对每个备选位置进行遍历和计算。但是,如果备选位置非常多,我们可以考虑使用更高效的数据结构(如KD树)来减少计算量(感兴趣的同学可以自行尝试代码优化哟,这里就不再给出具体优化的代码啦)。
3、问题扩展
这个问题可以扩展到考虑不同市民的权重,即不同市民到火车站的旅行时间对总时间的影响不同。这将涉及到加权曼哈顿距离的计算,感兴趣的同学可以自行尝试~~。