• 编程之美初赛第一场 题目3 : 活动中心


    题目3 : 活动中心

    时间限制:12000ms 单点时限:6000ms  内存限制:256MB

    描述

    A市是一个高度规划的城市,但是科技高端发达的地方,居民们也不能忘记运动和锻炼,因此城市规划局在设计A市的时候也要考虑为居民们建造一个活动中心,方便居住在A市的居民们能随时开展运动,锻炼强健的身心。

    城市规划局希望活动中心的位置满足以下条件:

    1. 到所有居住地的总距离最小。

    2. 为了方便活动中心的资源补给和其他器材的维护,活动中心必须建设在A市的主干道上。

    为了简化问题,我们将A市摆在二维平面上,城市的主干道看作直角坐标系平的X轴,城市中所有的居住地都可以看成二维平面上的一个点。

    现在,A市的城市规划局希望知道活动中心建在哪儿最好。

    输入

    第一行包括一个数T,表示数据的组数。

    接下来包含T组数据,每组数据的第一行包括一个整数N,表示A市共有N处居住地

    接下来N行表示每处居住地的坐标。

    输出

    对于每组数据,输出一行“Case X: Y”,其中X表示每组数据的编号(从1开始),Y表示活动中心的最优建造位置。我们建议你的输出保留Y到小数点后6位或以上,任何与标准答案的绝对误差或者相对误差在10-6以内的结果都将被视为正确。

    数据范围

    小数据:1 ≤ T ≤ 1000, 1 ≤ N ≤ 10

    大数据:1 ≤ T ≤ 10, 1 ≤ N ≤ 105

    对于所有数据,坐标值都是整数且绝对值都不超过106 

    样例解释

    样例1:活动中心的最优建造位置为(1.678787, 0)

    样例输入
    1
    3
    1 1
    2 2
    3 3
    
    样例输出
    Case 1: 1.678787


    
    

    三分法——求解凸性函数的极值问题

       二分法作为分治中最常见的方法,适用于单调函数,逼近求解某点的值。但当函数是凸性函数时,二分法就无法适用,这时三分法就可以“大显身手”~~

           如图,类似二分的定义Left和Right,mid = (Left + Right) / 2,midmid = (mid + Right) / 2; 如果mid靠近极值点,则Right = midmid;否则(即midmid靠近极值点),则Left = mid;

    程序模版如下:

    double Calc(Type a)
    
    {
        /* 根据题目的意思计算 */
    }
    
    void Solve(void)
    {
        double Left, Right;
        double mid, midmid;
        double mid_value, midmid_value;
        Left = MIN; Right = MAX;
        while (Left + EPS < Right)
        {
            mid = (Left + Right) / 2;
            midmid = (mid + Right) / 2;
            mid_area = Calc(mid);
            midmid_area = Calc(midmid);
            // 假设求解最大极值.
            if (mid_area >= midmid_area) Right = midmid;
            else Left = mid;
        }
    }

    现根据几道的OJ题目来分析三分法的具体实现。

    buaa 1033 Easy Problem 
    http://acm.buaa.edu.cn/oj/problem_show.php?c=0&p=1033

    题意为在一条线段上找到一点,与给定的P点距离最小。很明显的凸性函数,用三分法来解决。
    Calc函数即为求某点到P点的距离。

    ZOJ 3203 Light Bulb
    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3203

    如图,人左右走动,求影子L的最长长度。
    根据图,很容易发现当灯,人的头部和墙角成一条直线时(假设此时人站在A点),此时的长度是影子全在地上的最长长度。当人再向右走时,影子开始投影到墙上,当人贴着墙,影子长度即为人的高度。所以当人从A点走到墙,函数是先递增再递减,为凸性函数,所以我们可以用三分法来求解。

    下面只给出Calc函数,其他直接套模版即可。

    double Calc(double x)
    {
        return (h * D - H * x) / (D - x) + x;
    }

    heru 5081 Turn the corner 08年哈尔滨regional网络赛
    http://acm.hrbeu.edu.cn/index.php?act=problem&proid=5081

     

    汽车拐弯问题,给定X, Y, l, d判断是否能够拐弯。首先当X或者Y小于d,那么一定不能。
    其次我们发现随着角度θ的增大,最大高度h先增长后减小,即为凸性函数,可以用三分法来求解。

    这里的Calc函数需要比较繁琐的推倒公式:
    s = l * cos(θ) + w * sin(θ) - x;
    h = s * tan(θ) + w * cos(θ);
    其中s为汽车最右边的点离拐角的水平距离, h为里拐点最高的距离, θ范围从0到90。

    POJ 3301 Texas Trip
    http://acm.pku.edu.cn/JudgeOnline/problem?id=3301

    题意为给定n(n <= 30)个点,求出饱含这些点的面积最小的正方形。

    有两种解法,一种为逼近法,就是每次m分角度,求出最符合的角度,再继续m分,如此进行times次,即可求出较为精确的解。(m 大概取10, times取30即可)

    第二种解法即为三分法,首先旋转的角度只要在0到180度即可,超过180度跟前面的相同的。坐标轴旋转后,坐标变换为:
    X’ = x * cosa - y * sina;
    y’ = y * cosa + x * sina;

    至于这题的函数是否是凸性的,为什么是凸性的,我也无法给出准确的证明,希望哪位路过的大牛指点一下~~

    对于求解一些实际问题,当公式难以递推.

    本题AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #include<algorithm>
    #include<cmath>
    #include<string>
    #include<vector>
    #include<queue>
    using namespace std;
    double x[111111],y[111111];
    int n;
    double mi,ma;
    double dis(double xx,int k)
    {
       xx=xx-x[k];
       return sqrt(xx*xx+y[k]*y[k]);
    }
    int main()
    {
       int t;
       int ca=1;
       scanf("%d",&t);
       while(t--)
       {
           scanf("%d",&n);
           mi=0;
           ma=0;
           for(int i=0;i<n;i++)
           {
               scanf("%lf%lf",&x[i],&y[i]);
               mi=min(mi,x[i]);
               ma=max(ma,x[i]);
           }
           double low=mi,high=ma,mid,mmd;
           double l1,l2;
           while(high-low>1e-8)
           {
               mid=(low+high)/2;
               mmd=(mid+low)/2;
               l1=l2=0;
               for(int i=0;i<n;i++)
               {
                   l1+=dis(mid,i);
                   l2+=dis(mmd,i);
               }
               if(l1>l2)
               {
                   high=mid;
               }
               else low=mmd;
           }
           printf("Case %d: %.6f ",ca++,low);
       }
       return 0;
    }
  • 相关阅读:
    SpringCloud微服务初步认识
    SpringCloud-Hystrix:服务熔断与降级
    List接口下重要集合源码分析
    高频面试题:手写一个LRU
    Java基础面试题面经整理(持续更新)
    Redis高可用之主从复制
    Redis过期键删除和内存淘汰
    Redis持久化(RDB与AOF)
    了解Redis事务
    Redis入门与安装
  • 原文地址:https://www.cnblogs.com/crazyacking/p/3675364.html
Copyright © 2020-2023  润新知