• 洛谷 P2600 [ZJOI2008]瞭望塔


    洛谷 P2600 [ZJOI2008]瞭望塔

    洛谷传送门

    题目描述

    致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安。

    我们将H村抽象为一维的轮廓。如下图所示

    img

    我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。为了节省开支,dadzhi村长希望建造的塔高度尽可能小。

    请你写一个程序,帮助dadzhi村长计算塔的最小高度。

    输入格式

    输入文件tower.in第一行包含一个整数n,表示轮廓折线的节点数目。接下来第一行n个整数, 为x1 ~ xn. 第三行n个整数,为y1 ~ yn。

    输出格式

    输出文件tower.out仅包含一个实数,为塔的最小高度,精确到小数点后三位。


    题解:

    首先明确,它不一定是在最高的点修塔。很容易就能构造出一种反例来hack掉这种想法。

    所以直接选出建塔点之后枚举或二分长度这种想法破灭了。

    所以开始考虑选点的问题。

    咋选点呢?首先想到二分选点,但是这玩意并不是一个单调函数,理想破灭。

    ?等等,不单调,可不可以三分。

    可以!!

    欣喜若狂:发现如果往左建,就要花力气看看右侧的点,如果往右建,就要花力气看看左侧的点。这样的话就可以确定建塔处,至于塔高直接取所有线段反向延长后到此的最大值即可。

    应该还是很容易的,对三分不太熟悉的小伙伴可以参照这里:浅谈三分法

    代码:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int maxn=310;
    const double eps=1e-7;
    const double INF=1e20;
    int n;
    double ans=INF;
    struct node
    {
        double x,y;
    }p[maxn];
    struct edge
    {
        double k,b;
        bool f;//是否平
    }e[maxn];
    double calc(double x,double y)
    {
        double tmp=0;
        for(int i=1;i<n;i++)
        {
            if(!e[i].f) 
    			continue;
            tmp=fmax(tmp,e[i].k*x+e[i].b-y);
        }
        return tmp;
    }
    bool check(double x1,double x2,int i)
    {
    	return calc(x1,e[i].k*x1+e[i].b)<calc(x2,e[i].k*x2+e[i].b);
    }
    int main()
    {
    	// freopen("cold.in","r",stdin);
    	// freopen("cold.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) 
    		scanf("%lf",&p[i].x);
        for(int i=1;i<=n;i++) 
    		scanf("%lf",&p[i].y);
        for(int i=1;i<n;i++)
        {
            if(fabs(p[i].x-p[i+1].x)<eps) 
    			continue;//平
            e[i].k=(p[i].y-p[i+1].y)/(p[i].x-p[i+1].x);
            e[i].b=p[i].y-p[i].x*e[i].k;
            e[i].f=1;
        }
        for(int i=1;i<n;i++)
        {
            if(!e[i].f) 
    			continue;
            int t=612; 
    		double l=p[i].x; 
    		double r=p[i+1].x;
    		double mid1,mid2;
            while(t--)
            {
                mid1=l+(r-l)/3; 
    			mid2=r-(r-l)/3;
                if(check(mid1,mid2,i)) 
    				r=mid2;
                else 
    				l=mid1;
            }
            ans=fmin(ans,calc(mid1,e[i].k*mid1+e[i].b));
        }
        printf("%.3lf",ans);
    	return 0;
    }
    
  • 相关阅读:
    Git与GitHub关联
    利用GitHub上的SimpleMemory装扮博客园
    第5课第4节_Binder系统_C程序示例_测试与总结
    第5课第1节_Binder系统_C程序示例_框架分析
    第4课第4节_Android灯光系统_源码分析_电池灯
    第4课第3节_Android灯光系统_编写HAL_lights.c
    第2课第1节_Android灯光系统_led_class驱动
    第4课第1节_Android灯光系统_总体框架
    Android 优秀博客
    4.5节_Android硬件访问服务使用反射
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14019973.html
Copyright © 2020-2023  润新知