我有一行说L行,lx + my + n = 0
。现在,假设有一些K点在{L}线上的xy平面上说(x1,y1),(x2, y2)...(xk,yk)
,我想找到L行上的一个点,比如X (x0,y0)
,这样X与X之间的距离之和'N'点很少。解决这个问题的算法是什么?
我想到了一个解决方案,首先我发现点的坐标与每个点(x1,y1),(x2, y2)...(xk,yk)
的直线L相交。然后我找到所有那些点的平均点,其中垂线遇到线L以找到最小点。但这种做法是错误的。请建议正确的方法来解决问题。这是我的代码
#include <stdio.h>
#include <math.h>
typedef struct
{
int x;
int y;
}point;
double distance(point * A, double x, double y)
{
return sqrt(pow(A->x - x, 2) + pow(A->y - y, 2));
}
int main()
{
int i = 0 , j = 0, test = 0, number_of_warehouse = 0, A = 0, B = 0, C = 0;
point * point_array , *closest_points, sum;
double avgx = 0.0, avgy = 0.0, Total_dist = 0.0;
scanf("%d", &test);
while (test--)
{
scanf("%d", &number_of_warehouse);
point_array = malloc (sizeof(point) * number_of_warehouse);
closest_points = malloc (sizeof(point) * number_of_warehouse);
scanf("%d%d%d", &A, &B,&C);
sum.x = 0;
sum.y = 0;
avgx = 0;
avgy = 0;
for(i = 0; i < number_of_warehouse; ++i)
{
scanf("%d%d", &(point_array[i].x), &(point_array[i].y));
closest_points[i].x = (B*(B * point_array[i].x - A * point_array[i].y) - A *C)/ (A*A + B*B);
closest_points[i].y = (A*((-1)* B * point_array[i].x + A * point_array[i].y) - B *C)/ (A*A + B*B);
sum.x += closest_points[i].x;
sum.y += closest_points[i].y;
}
Total_dist = 0.0;
avgx = sum.x / number_of_warehouse;
avgy = sum.y / number_of_warehouse;
for(i = 0; i < number_of_warehouse; ++i)
{
Total_dist += distance(point_array + i, avgx, avgy);
}
printf("%.6f", Total_dist);
}
return 0;
}
答案 0 :(得分:2)
您可以使用least squares的方法进行适当的调整,因为您的问题有点不同。但是,这是一个过程的概述。
如果我们制作a = -l/m
和b = -n/m
,我们可以写:
y = ax + b
这意味着直线上的点的格式为(x ,ax + b)
,因此直线(x ,y )
中的任意点与集合的第i个点之间的距离为(xi, yi)
是:
di = sqrt [ (x - xi)^2 + (ax + b - yi)^2 ]
现在我们必须将0
的总和最小化为k
di
,这不是一个小问题。回归分析中通常的近似是最小化距离的平方,这有更简单的解决方案。
扩展我们的正方形和重构:
di^2 = x^2 *k*(1 + a^2) + x (-2xi + 2kab - 2ayi) + (k*b^2 + yi^2 - 2byi + xi^2)
现在,计算di^2
对i
的所有值的总和,并考虑到求和是一个线性算子,我们可以简单地将xi
替换为所有值的总和。 xi
,yi
,xi^2
和yi^2
也是如此(首先要小心计算平方值,然后将它们相加,尽管您不需要这些值)。对于不依赖于i
的条款,它们将乘以k
,因为它们将加k
次。
现在我们推导出di^2
的总和,并将其等于零,以求解x
d (di^2)/dx = 2k(1 + a^2) x + (-2*Sum(xi) + 2ab - 2a*Sum(yi)) = 0
最后,隔离x
我们获得:
x = (2*Sum(xi) - 2kab + 2a*Sum(yi))/2k(1+a^2)
和y
当然是ax + b
因此,您只需要以编程方式计算xi
和yi
的摘要,这应该非常简单。请检查代数,这也是理解该过程的一个很好的练习。
这是一个实现此算法并使用简单案例进行检查的示例程序。如果你的k点集合与你的点可以移动的直线垂直,那么最近的点应该是两条直线的交点。
#include <stdio.h>
#define NUM_OF_POINTS 5
typedef struct
{
double x;
double y;
}point;
point findPoint (point *points, double slope, double intercept)
{
int i;
double sum_x = 0, sum_y = 0;
point your_point;
for( i = 0; i < NUM_OF_POINTS; ++i)
{
sum_x += points[i].x;
sum_y += points[i].y;
}
your_point.x = 2*(sum_x - NUM_OF_POINTS*slope*intercept + slope*sum_y)/(2*NUM_OF_POINTS*(1+slope*slope));
your_point.y = slope*your_point.x + intercept;
return your_point;
}
int main()
{
int i = 0;
double slope = 1.0, intercept = 1.0;
point point_arr [NUM_OF_POINTS], closest_point;
//Generate points in the line normal to y = slope*x + intercept
for (i = 0; i < NUM_OF_POINTS; i++)
{
point_arr[i].x = 2.0 + i;
point_arr[i].y = (-1.0/slope)*point_arr[i].x + 3.0;
}
closest_point = findPoint (point_arr, slope, intercept);
printf("Your point is %f, %f\n", closest_point.x, closest_point.y);
return 0;
}
直线为y = x + 1
,点在法线y = -x + 3
中生成。结果是点(1,2)
,它是两条线的交点。
DP
答案 1 :(得分:1)
点P的轨迹使得P与给定的固定n点(不是所有共线)的距离之和是恒定的(比如说D)是一个凸集,称为n-椭圆,相应的n-椭圆用于距离对于D',对于D',D'完全位于n-椭圆内。 D.(2椭圆是实际的椭圆)
因此,在给定线上的点之间存在唯一的(全局)最小值,并且爬山算法将起作用。
请参阅此文件:n-ellipses and the minimum distance problem以获取上述声明的证据。
@DissidentPenguin:最小化x_1 + x_2与最小化sqrt(x_1)+ sqrt(x_2)(你对sqrt(x_1 + x_2)混淆)不同。
答案 2 :(得分:1)
您可以在数学上将解决方案表示为: -
lx + my + n = 0
and
Say you want to minimize squared distances then :-
S = sum((xk-x)^2 + (yk-y)^2) for all N points.
y = (n-mx)/l from line equation
S = sum((xk-x)^2 + (yk-(n-mx)/l)^2)
S = sum((xk-x)^2 + (ykl-n+mx)^2/l^2))
Diff wrt to x for minimizing
S = sum(2*(xk-x) + 2m*(ykl-n+mx)/l^2) = 0
Distributing summation
S = sum(xk) - sum(x) + (m/l^2)*( l*sum(yk) - sum(n) + m*sum(x))) = 0
S = sum(xk) - N*x + (m/l^2)*(l*sum(yk) - N*n + m*N*x) = 0
(1-m^2/l^2)*N*x = sum(xk) + (m/l^2)*(l*sum(yk)-N*n)
Find x using the equation and then find y using line equation
答案 3 :(得分:-1)
我认为没有封闭形式的解决方案。
这意味着您必须使用数字近似值。
即,您需要实现函数double tot_dist(double x)
,其中x
是您线上的坐标,tot_dist
计算距离的总和。
然后,您需要将其传递给可用的大量最小发现功能之一(例如,Mathematica,R:optim,optimize)。
如果您将点x
沿着线移动一小段距离h
,x
到X_k
之间的距离将会更改h*cos(a)
其中{ {1}}是第a
行与第L
行之间的角度。这意味着您的解决方案满足了很好的等式xX_k
,即,您可以使用Newton's method来查找sum(cos(a_k))=0
函数的零(而不是使用通用最小化器)(您将需要计算double sum_cos_angle(double x)
的导数,但这不应该是一个大问题。
建议的Voronoi diagram解决方案 不适用于此处,因为这是全局问题(距所有点的距离),以及Voronoi用于本地问题(最接近的一个点)。基本上,如果我们摆动一个点sum_cos_angle
,这个问题的解决方案就会改变。另一方面,Voronoi图仅取决于最接近的2个点的位置,因此,如果我们摆动单个远点,图表将不会改变,因此,使用它获得的任何解决方案都将不要改变。