一、题目分析
分析题目可知,所求解是一个二维空间中的某点。可以参照一维空间中的三分法查找找到最优值。
如下图:最优点一下位于谷底处:
仿照三分法,在空间中找到四个点,依次为0,1,2,3:
计算这个四点的距离值,找出最大值和最小值:
假设红色点是最小值点,绿色为最大值点,可以推断最优点一定在红色点附近,那么就可以将搜索空间缩小,即按黑色箭头指示方向缩小空间,然后重复此过程,直到满足精度要求。
在搜索空间过程中要注意到如果最小值点与最大值点挨着的情况下,按上面的过程缩小空间可能会将最优点去除(第一次就是没有考虑这种情况失败了,修改后通过~_~),所以要判断最小值点与最大值点关系,然后选择缩小空间的方向,如图:
只能向一个方向缩小空间。
二、通过代码
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
#ifdef WIN32
typedef __int64 ll;
#else
typedef long long ll;
#endif
double max(double x, double y)
{
return x > y ? x : y;
}
double cal(double px, double py, int n, const int *x, const int *y)
{
double res = 0;
for(int i = 0; i < n; ++i)
{
res += max(fabs(px - x[i]), fabs(py - y[i]));
}
return res;
}
int cmp(double *smallest, int *code, double *distance)
{
int index = 0;
*smallest = distance[0];
*code = 0;
for(int i = 1; i < 4; ++i)
{
if(distance[index] < distance[i])
{
index = i;
}
if(*smallest > distance[i])
{
*smallest = distance[i];
*code = i;
}
}
return index;
}
bool isFinish(double *distance)
{
bool res = false;
double sum = 0;
double delta = 0;
for(int i = 0; i < 4; ++i)
{
sum += distance[i];
}
sum /= 4;
for(int i = 0; i < 4; ++i)
{
delta += fabs(sum - distance[i]);
}
if(delta / 4 < 1e-4)
{
res = true;
}
return res;
}
double bestDistance(int n, const int *x,const int *y)
{
double xl_down, yl_down;
double xl_up, yl_up;
double xr_down, yr_down;
double xr_up, yr_up;
double res = 1000000000000000000;
double cur = 1000000000;
double xtmp[4];
double ytmp[4];
xl_down = -1000000000;
yl_down = -1000000000;
xl_up = -1000000000;
yl_up = 1000000000;
xr_down = 1000000000;
yr_down = -1000000000;
xr_up = 1000000000;
yr_up = 1000000000;
double distance[4];
while(1)
{
//上左
xtmp[0] = xl_up + (xr_up - xl_up) / 3;
ytmp[0] = yl_up - (yl_up - yl_down) / 3;
distance[0] = cal(xtmp[0], ytmp[0], n, x, y);
//上右
xtmp[1] = xr_up - (xr_up - xl_up) / 3;
ytmp[1] = yl_up - (yl_up - yl_down) / 3;
distance[1] = cal(xtmp[1], ytmp[1], n, x, y);
//下左
xtmp[2] = xl_down + (xr_down - xl_down) / 3;
ytmp[2] = yl_down + (yl_up - yl_down) / 3;
distance[2] = cal(xtmp[2], ytmp[2], n, x, y);
//下右
xtmp[3] = xr_down - (xr_down - xl_down) / 3;
ytmp[3] = yr_down + (yr_up - yr_down) / 3;
distance[3] = cal(xtmp[3], ytmp[3], n, x, y);
int s_index;
int index = cmp(&cur, &s_index, distance);
if(cur < res)//更新最新的值
{
res = cur;
}
if(isFinish(distance))//是否达到精度要求
{
break;
}
switch(index)
{
case 0://上左
if(s_index == 1)
{
xl_up = xtmp[0];
xl_down = xtmp[0];
}
else if(s_index == 2)
{
yl_up = ytmp[0];
yr_up = ytmp[0];
}
else
{
xl_up = xtmp[0];
yl_up = ytmp[0];
xl_down = xtmp[0];
yr_up = ytmp[0];
}
break;
case 1://上右
if(s_index == 0)
{
xr_up = xtmp[1];
xr_down = xtmp[1];
}
else if(s_index == 3)
{
yr_up = ytmp[1];
yl_up = ytmp[1];
}
else
{
xr_up = xtmp[1];
yr_up = ytmp[1];
xr_down = xtmp[1];
yl_up = ytmp[1];
}
break;
case 2://下左
if(s_index == 0)
{
yl_down = ytmp[2];
yr_down = ytmp[2];
}
else if(s_index == 3)
{
xl_down = xtmp[2];
xl_up = xtmp[2];
}
else
{
xl_down = xtmp[2];
yl_down = ytmp[2];
xl_up = xtmp[2];
yr_down = ytmp[2];
}
break;
case 3://下右
if(s_index == 1)
{
yr_down = ytmp[3];
yl_down = ytmp[3];
}
else if(s_index == 2)
{
xr_down = xtmp[3];
xr_up = xtmp[3];
}
else
{
xr_down = xtmp[3];
yr_down = ytmp[3];
xr_up = xtmp[3];
yl_down = ytmp[3];
}
break;
default:
printf("error\n");
}
}
return res;
}
int main()
{
double res;
//int n = 4;
// int x[] = {1, 2, 0, 1};
// int y[] = {4, 3, 1, 1};
int n = 19;
int x[] = {858442934,-161749718,-55910439,347569202,-660170269,-982075453,-860790164,947179323,312298821,-285196111,967545126,-777105315,-630974471,-713895350,745616673,840630174,-597730146,-205693089,24677872};
int y[] = {449535070,160026431,705809990,121634879,648304545,-392329548,-447666131,-829918127,926665890,943182185,601133076,-848803337,89719473,-586785144,832132969,-111884761,-556530757,65860874,978639057};
res = bestDistance(n, x, y);
printf("%f\n", res);
return 0;
}