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 }
  • 相关阅读:
    LeetCode 24. Swap Nodes in Pairs (两两交换链表中的节点)
    LeetCode 1041. Robot Bounded In Circle (困于环中的机器人)
    LeetCode 1037. Valid Boomerang (有效的回旋镖)
    LeetCode 1108. Defanging an IP Address (IP 地址无效化)
    LeetCode 704. Binary Search (二分查找)
    LeetCode 744. Find Smallest Letter Greater Than Target (寻找比目标字母大的最小字母)
    LeetCode 852. Peak Index in a Mountain Array (山脉数组的峰顶索引)
    LeetCode 817. Linked List Components (链表组件)
    LeetCode 1019. Next Greater Node In Linked List (链表中的下一个更大节点)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/10549114.html
Copyright © 2011-2022 走看看