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;
    }
  • 相关阅读:
    软件需求阅读笔记02
    软件需求阅读笔记01
    搜狗输入法
    冲刺周之后感想
    典型用户分析和场景
    四则运算
    学习总结
    2019年春阅读笔记5——对开源的认知
    2019年春阅读笔记4——分布式消息系统的现状、挑战与未来
    2019年春阅读笔记3——数据库集群方案
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4534477.html
Copyright © 2011-2022 走看看