問題の説明:
全部でN点あります。すべてのポイントは特定の方向と特定の速度で移動します。任意の2点間の最大距離が最小になるのはいつかを知りたいのです。また、その最小距離を計算する必要があります。2つのポイントがまったく同じ速度と方向に移動しないことを保証します。
入力の説明:
最初の行には、テストケースの数を示す番号T(T <= 10)があります。
テストケースごとに、最初の行には、ポイントの数である単一の数値N(N <= 300)があります。
次のN行の場合、それぞれに4つの整数Xi、Yi、VXi、およびVYi(-106 <= Xi、Yi <= 106、-102 <= VXi、VYi <= 102)があり、(Xi、Yi)は次の位置です。 i番目の点、および(VXi、VYi)は、方向による速度です。つまり、1秒後、このポイントは(Xi + VXi、Yi + VYi)に移動します。
出力の説明:
テストケースXの場合、最初に「ケース#X:」を出力してから、時間と距離の答えとして、0.01に丸められた2つの数値を出力します。
サンプル入力:
2
2
0 0 1 0
2 0 -1 0
2
0 0 1 0
2 1 -1 0
サンプル出力:
ケース#1:1.00 0.00
ケース#2:1.00 1.00
アイデア:
被験者の意識は、私たち2点間の最大距離の最小値です。二分法を使用して最小値を見つけ、2点間の距離を取得する関数を事前に記述し、二分法の精度が十分に小さいことを確認するように注意してください。
ACコード:
#include <bits/stdc++.h>
using namespace std;
int n;
double a[1000],b[1000],c[1000],d[1000];
double distance(int m,int n,double t)
{
double x1=a[m]+t*c[m],x2=a[n]+t*c[n];
double y1=b[m]+t*d[m],y2=b[n]+t*d[n];
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double check(double t)
{
double ans=0.0;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
ans=max(ans,distance(i,j,t));
}
}
return ans;
}
int main()
{
int T;
cin>>T;
int cas=0;
while(T--)
{
cin>>n;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf",&a[i],&b[i],&c[i],&d[i]);
}
double l=0.0,r=100000000000.0,time=0.0,path=10000000000000.0;
while(l+1e-11<=r)
{
double middle1=(l+r)/2;
double middle2=(middle1+r)/2;
if(check(middle1)<=check(middle2))
r=middle2;
else l=middle1;
if(path>check(l))
{
time=l;
path=check(l);
}
}
cout<<"Case #"<<++cas<<": "<<fixed<<setprecision(2)<<time<<' '<<path<<endl;
}
return 0;
}