zoukankan      html  css  js  c++  java
  • P2600 [ZJOI2008]瞭望塔(半平面交)

    题目描述

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

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

    我们可以用一条山的上方轮廓折线(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仅包含一个实数,为塔的最小高度,精确到小数点后三位。

    输入输出样例

    输入样例#1: 复制
    6
    1 2 4 5 6 7
    1 2 2 4 2 1
    
    输出样例#1: 复制
    1.000

    说明

    对于60%的数据, N ≤ 60;

    对于100%的数据, N ≤ 300,输入坐标绝对值不超过106,注意考虑实数误差带来的问题。






    首先,塔i顶的位置属于一个区域:有所有相邻的两个点确定直线的组成的凸包

    然后出现了许多分段的一次函数,断电是地面上的焦点和凸包的拐,然后最值从端点出取得

    因此枚举地面上的焦点和凸包的拐点都算一遍就行了,因为这题的数据比较小,也可以枚举每两条直线的焦点算一遍qwq

    然后还有第二种做法就是,考虑地面上的每一个线段,有一个理解是:

    瞭望塔建的靠左,为了能看到右边的,要高一点

    瞭望塔建的靠右,为了能看到左边的,要高一点

    对于任意相意两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数

    三分就完事了

    不用(hui)证明 - -

    给出第一个做法的码:




     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 using namespace std;
     6 typedef double db;
     7 const int N=305;
     8 const db inf=99999999999.0;
     9 int n;
    10 db ax[N],ay[N];
    11 struct LINE{
    12     db k,b; //y=kx+b
    13 }ln[N];
    14 db ans=inf;
    15 db sol(db x){ //计算特定横坐标的最小瞭望塔高度
    16     db res=0;
    17     for(int i=1;i<n;i++)
    18         res=max(res,ln[i].k*x+ln[i].b);
    19     return res;
    20 }
    21 int main(){
    22     scanf("%d",&n);
    23     for(int i=1;i<=n;i++)
    24         scanf("%lf",&ax[i]);
    25     for(int i=1;i<=n;i++)
    26         scanf("%lf",&ay[i]);
    27     for(int i=1;i<n;i++){
    28         ln[i].k=(ay[i]-ay[i+1])/(ax[i]-ax[i+1]);
    29         ln[i].b=ay[i]-ln[i].k*ax[i];
    30     }
    31     for(int i=1;i<=n;i++)
    32         ans=min(ans,sol(ax[i])-ay[i]); //先枚举每个端点
    33     for(int i=1;i<n;i++)
    34         for(int j=i+1;j<n;j++){
    35             db x=(ln[i].b-ln[j].b)/(ln[j].k-ln[i].k); //求两直线的交点
    36             for(int k=1;k<n;k++)
    37                 if(ax[k]<=x&&x<=ax[k+1])
    38                     ans=min(ans,sol(x)-ln[k].k*x-ln[k].b); //最小化答案
    39         }
    40     printf("%.3lf
    ",ans);
    41     return 0;
    42 }
  • 相关阅读:
    【python】opencv教程CV2模块——图片处理,裁剪缩放加边框
    【python】opencv教程CV2模块——画图,来左边跟我一起画星星在右边画彩虹
    【python】opencv教程CV2模块——图片处理,剪切缩放旋转
    【python】opencv教程CV2模块——批量视频截屏
    【python】opencv教程CV2模块——视频捕获,延时摄影视频、鬼畜表情包密集制作
    代码-JS之正则验证邮箱格式
    代码-JS之正则解决结巴程序
    代码-JS之IE+GOOGLE兼容函数
    代码-JS之正则replace函数
    代码-JS之下拉菜单
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/10549114.html
Copyright © 2011-2022 走看看