zoukankan      html  css  js  c++  java
  • ACM学习历程—HDU4717 The Moving Points(模拟退火 || 三分法)

    Description

    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 th point, 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

    题目大意就是给定n个点的坐标和它x和y方向的分速度,要求在任意时刻两两点之间距离最大值中的最小值。

    根据距离公式可以推断出对于某两个点在t逐渐增大的过程中距离服从二次函数。

    于是就是对于n个二次抛物线求任意时刻最高点合成的图像。

    可以证明(反证)合成的图像也是由两个单调性相反的图像构成(类似于抛物线)。

    于是可以采用模拟退火的退化(类似爬山算法)来查找最值。

    从minT从0时刻出发,首先设定步长dt = 1e8。然后对于minT-dt和minT+dt讨论,如果使最大值变小,自然更新minT,然后按比例k衰减dt。

    直到dt满足精度要求。

    进过测试比例k=0.9是可以满足的,跑了530MS;k = 0.95略慢些,跑了1.3S。

    网上也有好多使用的是三分法。

    这里贴出退火的代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <vector>
    #include <queue>
    #include <string>
    #define LL long long
    #define eps 1e-5
    
    using namespace std;
    
    typedef pair<double, double> pdd;
    
    int x[305], y[305], vx[305], vy[305], n;
    double minT, minDis;
    
    double pow2(double k)
    {
        return k*k;
    }
    
    double calDis(double t)
    {
        double dis2 = 0;
        for (int i = 0; i < n; ++i)
        {
            for (int j = i+1; j < n; ++j)
            {
                if (i == j)
                    continue;
                dis2 = max(dis2,
                           pow2(x[i]+vx[i]*t-x[j]-vx[j]*t) + pow2(y[i]+vy[i]*t-y[j]-vy[j]*t));
            }
        }
        return sqrt(dis2);
    }
    
    void qt()
    {
        double dt = 1e8, t, dis, k = 0.9, v;
        minT = 0;
        minDis = calDis(minT);
    
        while (dt > eps)
        {
            dis = calDis(minT+dt);
            t = minT + dt;
            if (minT-dt >= 0)
            {
                v = calDis(minT-dt);
                if (v < dis)
                {
                    dis = v;
                    t = minT - dt;
                }
            }
            if (dis < minDis)
            {
                minDis = dis;
                minT = t;
            }
            dt *= k;
        }
    }
    
    void Work()
    {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i)
            scanf("%d%d%d%d", &x[i], &y[i], &vx[i], &vy[i]);
        qt();
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            printf("Case #%d: ", times);
            Work();
            printf("%.2lf %.2lf
    ", minT, minDis);
        }
        return 0;
    }
  • 相关阅读:
    KNN算法
    mysql必须知道的
    励志的演讲
    30条程序员名言警句
    别人的文章:为什么软件开发,人多,事少,还会工作量大?
    分享一个比较受启发的文章“学历代表过去,能力代表现在,学习力代表未来”
    mvc 学前必知
    启动docker容器 防火墙问题报错 ! -i docker0' failed: iptables: No chain/target/match by that name.
    git指令详解总结
    git reset 版本回退的三种用法总结
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4534477.html
Copyright © 2011-2022 走看看