在平面上有N个点,他们有各自的速度向量。现在我们给出时刻0时他们的位置
由于速度不变,所以解函数是个凹函数,凹函数的梯度是左边小于0,右边大于0。
可以根据梯度,使用二分查找梯度为0 的位置。
题目没有限制t的范围,注意初始查找的区域设定:
不能太大,如果太大,会造成计算距离溢出,而且会计算过程中会发生精度丢失,导致梯度计算错误。
不能太小,如果太小,区域很可能没有包含解的位置
试了半天,99999999999应该可以。
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <iomanip>
#include <limits>
using namespace std;
int N;
struct dot
{
double x;
double y;
double vx;
double vy;
};
vector<dot> dotvec;
inline double getdis(int left, int right, double time)
{
dot dot1 = dotvec[left];
dot dot2 = dotvec[right];
dot1.x = dot1.x + dot1.vx*time;
dot1.y = dot1.y + dot1.vy*time;
dot2.x = dot2.x + dot2.vx*time;
dot2.y = dot2.y + dot2.vy*time;
double dis(0);
double x = dot1.x - dot2.x;
double y = dot1.y - dot2.y;
double sum = pow(x, 2) + pow(y, 2);
dis = pow(sum, 0.5);
return dis;
}
double getspecial(double time)
{
double max_dis(0);
for (auto i = 0; i < dotvec.size(); ++i)
{
for (auto j = i+1; j < dotvec.size(); ++j)
{
double dis = getdis(i, j, time);
max_dis = max(max_dis, dis);
}
}
return max_dis;
}
double func()
{
double left(0);
double right = 99999999999;
double midleft, midright(0);
double dis_midleft, dis_midright;
while (right - left>0.001)
{
midleft = (right + left) / 2;
midright = midleft + 0.0001;
dis_midleft = getspecial(midleft);
dis_midright = getspecial(midright);
if (dis_midleft<dis_midright)
{
right = midleft;
}
else
{
left = midleft;
}
}
cout.flags(ios::fixed);
cout.precision(2);
cout << midleft << " " << dis_midleft << endl;
return midleft;
}
int main()
{
while (cin >> N)
{
dot d;
dotvec.clear();
for (auto i = 0; i < N; ++i)
{
cin >> d.x;
cin >> d.y;
cin >> d.vx;
cin >> d.vy;
dotvec.push_back(d);
}
func();
}
return 0;
}