取物资
在一个二维地图上有很多军营,每个军营的坐标为(x,y)(x,y),现在你要在xx轴上设置一个补给站,补给站不一定要在整点上,现在想让军营到补给站的距离的最大值最小。
请问最小的最大距离是多少?
兵营的数量小于等于10^4
坐标(x,y)保证0 <= |x|, |y| <= 10000
分析
由题知补给站到军营的距离符合二次函数变化规律。在给定的军营坐标集合中,补给站到军营的最大距离最小的点一定在给定的军营的最小横坐标到最大横坐标
之间,并且越往中间最大距离的值越小。符合三分查查找算法的特征
算法
算法过程如下
-
取l为给定军营集合的横坐标的最小值,r为给定军营集合的最大值,利用三分法查找补给点
-
每次取中点和3/4点,优化l,r
-
由于补给点可能为小数,因此我们需要通过控制三分查找的次数,以控制精度。通常循环次数越多精度越高
具体实现
package com.aim.algorithm;
public class SupplyStation {
public static void main(String args[]){
int[][] barracks = new int[3][2];
barracks[0][0] = 0;
barracks[0][1] = 0;
barracks[1][0] = 0;
barracks[1][1] = 2;
barracks[2][0] = 2;
barracks[2][1] = 0;
System.out.println(fetchSuppliesII(barracks));
}
/**
* @param barracks: the position of barracks
* @return: the minimum of the maximum of the distance
*/
public static double fetchSuppliesII(int[][] barracks) {
// write your code here
double l = Integer.MAX_VALUE;
double r = Integer.MIN_VALUE;
for (int i = 0; i < barracks.length; i++) {
for (int j = 0; j < barracks[i].length; j++) {
if (barracks[i][j] < l) {
l = barracks[i][j];
}
if (barracks[i][j] > r) {
r = barracks[i][j];
}
}
}
int loop = 100;
double mid = 0;
for (int i = 0; i < loop; i++) {
mid = l + (r - l) / 2;
double midmid = mid + (r - mid) / 2;
if(maxDistance(mid, barracks) > maxDistance(midmid, barracks)){
l = mid;
} else {
r = midmid;
}
}
return maxDistance(mid, barracks);
}
private static double maxDistance(double x, int[][] barracks) {
double maxDistance = Double.MIN_VALUE;
for (int i = 0; i < barracks.length; i++) {
double distance = Math.sqrt((barracks[i][0] - x) * (barracks[i][0] - x) + (barracks[i][1]*barracks[i][1]));
if(maxDistance < distance){
maxDistance = distance;
}
}
return maxDistance;
}
}
知识点整理
三分查找算法
三分查找法是用于查找二次函数,极值问题的算法。类似于二分查找,某值的过程。但二分查找是在一次函数中确定某个值,要求数组是单调的。三分查找面对的是呈二次函数规则分配的数组的极值算法,对于二次函数分布的数据二分查找无能为力。
三分查找算法过程如下
-
确定查找左边界l,右边界r
-
取l至r中间点mid,取l至r 3/4 点midmid
-
比较mid、midmid对应值,若mid > midmid,则l = mid; 若mid <= midmid,则取r = midmid
-
循环取中间点,3/4点逻辑并比较值,移动l、r值,使得无限趋近于极值