有一条线段 \(AB\),\(A\)、\(B\) 均在格点上。平面内有一点 \(P\),\(P\) 也在格点上。过 \(P\) 点做 \(PM\) \(\perp\) \(AB\),垂足为点 \(M\) .求线段 \(PM\) 的长。
介绍一种数学方法。
设 \(A(x_A,y_A)\), \(B(x_B,y_B)\), \(P(x_P,y_P)\).
易求得直线 \(AB\) 直线方程
\[AB:y=\frac{y_A-y_B}{x_A-x_B} \cdot x + \frac{x_Ay_B-x_By_A}{x_A-x_B}\]
也可以求得直线 \(PM\) 直线方程
\[PM:y=-\frac{x_A-x_B}{y_A-y_B}\cdot x+\frac{x_A-x_B}{y_A-y_B} \cdot x_P+y_P\]
联立成为方程组,解得
\[x_M = \frac{(x_A-x_B)(x_Ax_P-x_Bx_P+y_Ay_P-y_By_P)-(y_A-y_B)(x_Ay_B-x_By_A)}{(x_A - x_B)^2+(y_A-y_B)^2}\]
\[y_M = \frac{x_P(x_A-x_B)(y_A-y_B)+(x_A-x_B)(x_Ay_B-x_By_A)+y_p(y_A-y_B)^2}{(x_A - x_B)^2+(y_A-y_B)^2}\]
所以可以将 \(M\) 坐标出来
\[M (\frac{(x_A-x_B)(x_Ax_P-x_Bx_P+y_Ay_P-y_By_P)-(y_A-y_B)(x_Ay_B-x_By_A)}{(x_A - x_B)^2+(y_A-y_B)^2}, \frac{x_P(x_A-x_B)(y_A-y_B)+(x_A-x_B)(x_Ay_B-x_By_A)+y_p(y_A-y_B)^2}{(x_A - x_B)^2+(y_A-y_B)^2})\]
那么最后两点间距离公式套一下就出来了。
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
double x_A, x_B, x_P, y_A, y_B, y_P;
double x_M, y_M;
int main()
{
cin >> x_A >> y_A;
cin >> x_B >> y_B;
cin >> x_P >> y_P;
x_M = ( ( x_A - x_B ) * ( x_A * x_P - x_B * x_P + y_A * y_P - y_B * y_P ) - ( y_A - y_B ) * ( x_A * y_B - x_B * y_A ) ) /
( ( x_A - x_B ) * ( x_A - x_B ) + ( y_A - y_B ) * ( y_A - y_B ) );
y_M = ( x_P * ( x_A - x_B ) * ( y_A - y_B ) + ( x_A - x_B ) * ( x_A * y_B - x_B * y_A ) + ( y_A - y_B ) * ( y_A * y_P - y_B * y_P ) ) /
( ( x_A - x_B ) * ( x_A - x_B ) + ( y_A - y_B ) * ( y_A - y_B ) );
//cout << x_M << " " << y_M << endl;
cout << setiosflags( ios::fixed ) << setprecision( 0 ) << sqrt( ( x_P - x_M ) * ( x_P - x_M ) + ( y_P - y_M ) * ( y_P - y_M ) );
return 0;
}