The Moving Points HDU - 4717(三分)

There are N points in total. Every point moves in certain direction and certain speed. We want to know at what time that the largest distance between any two points would be minimum. And also, we require you to calculate that minimum distance. We guarantee that no two points will move in exactly same speed and direction.

Input

The rst line has a number T (T <= 10) , indicating the number of test cases. 
For each test case, first line has a single number N (N <= 300), which is the number of points. 
For next N lines, each come with four integers X i, Y i, VX i and VY i (-10 6 <= X i, Y i <= 10 6, -10 2 <= VX i , VY i <= 10 2), (X i, Y i) is the position of the i thpoint, and (VX i , VY i) is its speed with direction. That is to say, after 1 second, this point will move to (X i + VX i , Y i + VY i).

Output

For test case X, output "Case #X: " first, then output two numbers, rounded to 0.01, as the answer of time and distance.

Sample Input

2
2
0 0 1 0
2 0 -1 0
2
0 0 1 0
2 1 -1 0

Sample Output

Case #1: 1.00 0.00
Case #2: 1.00 1.00

思路:据说可以证明,两点间的距离满足抛物线的性质,先曾后减,所以可以三分来做。

下面的解析来自:https://blog.csdn.net/pi9nc/article/details/9666627

我们都知道 二分查找 适用于单调函数中逼近求解某点的值。

如果遇到凸性或凹形函数时,可以用三分查找求那个凸点或凹点。

下面的方法应该是三分查找的一个变形。

如图所示,已知左右端点L、R,要求找到白点的位置。

思路:通过不断缩小 [L,R] 的范围,无限逼近白点。

做法:先取 [L,R] 的中点 mid,再取 [mid,R] 的中点 mmid,通过比较 f(mid) 与 f(mmid) 的大小来缩小范围。

           当最后 L=R-1 时,再比较下这两个点的值,我们就找到了答案。

1、当 f(mid) > f(mmid) 的时候,我们可以断定 mmid 一定在白点的右边。

反证法:假设 mmid 在白点的左边,则 mid 也一定在白点的左边,又由 f(mid) > f(mmid) 可推出 mmid < mid,与已知矛盾,故假设不成立。

所以,此时可以将 R = mmid 来缩小范围。

2、当 f(mid) < f(mmid) 的时候,我们可以断定 mid 一定在白点的左边。

反证法:假设 mid 在白点的右边,则 mmid 也一定在白点的右边,又由 f(mid) < f(mmid) 可推出 mid > mmid,与已知矛盾,故假设不成立。

同理,此时可以将 L = mid 来缩小范围。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
const double eps=1e-8;
int n;
double vx[maxn],vy[maxn];
struct Point
{
    double x,y;
}p[maxn];
double sqr2(double a)
{
    return a*a;
}
double cal(double mid)
{
    double ans=0.f;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            double x1=p[i].x+vx[i]*mid;
            double x2=p[j].x+vx[j]*mid;
            double y1=p[i].y+vy[i]*mid;
            double y2=p[j].y+vy[j]*mid;
            ans=max(ans,sqrt(sqr2(x1-x2)+sqr2(y1-y2)));
        }
    }
    return ans;
}
pair<double,double > three_devide()
{
    double l=0,r=1e10;
    double tmp1,tmp2;
    while(r-l>=eps)
    {
        double mid=(l+r)*0.5;
        double mmid=(mid+r)*0.5;
        tmp1=cal(mid);
        tmp2=cal(mmid);
        if(tmp2>=tmp1) 
        {
            r=mmid-eps;
        }
        else
        {
            l=mid+eps;
        }
    }
    return make_pair(l,tmp1);
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T;
    cin>>T;
    int Case=0;
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&vx[i],&vy[i]);
        }
        pair<double,double> ans=three_devide();
        printf("Case #%d: ",++Case);
        printf("%.2lf %.2lf\n",ans.first,ans.second);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/82291520