在平面上有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;
}