zoukankan      html  css  js  c++  java
  • [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,注意考虑实数误差带来的问题

    这题分两步。第一步就是求出满足条件的半平面,这半部分就是"水平可见直线"那题。

    第二部就是计算答案。可以证明瞭望塔的横坐标一定在半平面或地面的拐点处,因为中间部分一定没有其中一端优秀。

    所以对半平面和地面的拐点分别拎出来讨论一下就好了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 struct Line
     8 {
     9   double k,b;
    10 }line[10001],sta[10001];
    11 int n,top;
    12 double x[1002],y[1001],inf=1e8,eps=1e-10,ans=2e12;
    13 int dcmp(double X)
    14 {
    15   if (X>eps) return 1;
    16   if (X<-eps) return -1;
    17   return 0;
    18 }
    19 double getx(Line a,Line b)
    20 {
    21   return ((b.b-a.b)/(a.k-b.k));
    22 }
    23 double gety(double X)
    24 {int i;
    25   for (i=1;i<=n;i++)
    26     {
    27       if (x[i+1]>=X) break;
    28     }
    29   if (i==n+1) return -inf;
    30   double k=(y[i+1]-y[i])/(x[i+1]-x[i]),b=y[i]-k*x[i];
    31   return X*k+b;
    32 }
    33 bool cmp(Line a,Line b)
    34 {
    35   if (dcmp(a.k-b.k)==0)
    36     return a.b<b.b;
    37   return a.k<b.k;
    38 }
    39 int main()
    40 {
    41   int i,j;
    42   double maxx;
    43   cin>>n;
    44   for (i=1;i<=n;i++)
    45     scanf("%lf",&x[i]);
    46   for (i=1;i<=n;i++)
    47     scanf("%lf",&y[i]);
    48   for (i=1;i<=n-1;i++)
    49     {
    50       line[i].k=(y[i+1]-y[i])/(x[i+1]-x[i]);
    51       line[i].b=y[i]-line[i].k*x[i];
    52     }
    53   n--;
    54   sort(line+1,line+n+1,cmp);
    55   line[n+1].k=inf;
    56   sta[1]=line[1];sta[2]=line[2];
    57   top=2;
    58   for (i=3;i<=n;i++)
    59     {
    60       if (dcmp(line[i].k-line[i+1].k)==0)
    61     continue;
    62       while (top>1&&getx(line[i],sta[top-1])<=getx(sta[top],sta[top-1])) top--;
    63       top++;
    64       sta[top]=line[i];
    65     }
    66   for (i=1;i<top;i++)
    67     {
    68       double X=getx(sta[i],sta[i+1]);
    69       double Y=sta[i].k*X+sta[i].b;
    70       if (dcmp(Y-gety(X))>=0)
    71       ans=min(ans,Y-gety(X));
    72     }
    73   for (i=1;i<=n+1;i++)
    74     {
    75       maxx=0;
    76       for (j=1;j<=top;j++)
    77     {
    78       maxx=max(maxx,x[i]*sta[j].k+sta[j].b);
    79     }
    80       if (dcmp(maxx-y[i])>=0)
    81       ans=min(ans,maxx-y[i]);
    82     }
    83   printf("%.3lf
    ",ans);
    84 }
    View Code

    本题可以使用三分法

    将点按横坐标排好序后

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

    感性理解单峰就是

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

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

    所以 枚举所有线段,三分线段上建造瞭望塔的位置,所有线段上的瞭望塔高度取最小

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 struct Node
     8 {
     9   double k,b;
    10   int pd;
    11 }L[1001];
    12 int n;
    13 double px[1001],py[1001],eps=1e-8,ans;
    14 int dcmp(double x)
    15 {
    16   if (x>eps) return 1;
    17   if (x<-eps) return -1;
    18   return 0;
    19 }
    20 double cal(double X,double Y)
    21 {int i;
    22   double tmp=0;
    23   for (i=1;i<n;i++)
    24     {
    25       if (L[i].pd==0) continue;
    26       tmp=max(tmp,L[i].k*X+L[i].b-Y);
    27     }
    28   return tmp;
    29 }
    30 int main()
    31 {int i;
    32   cin>>n;
    33   for (i=1;i<=n;i++)
    34     scanf("%lf",&px[i]);
    35   for (i=1;i<=n;i++)
    36     scanf("%lf",&py[i]);
    37   for (i=1;i<n;i++)
    38     {
    39       if (dcmp(px[i]-px[i+1])==0) continue;
    40       L[i].k=(py[i]-py[i+1])/(px[i]-px[i+1]);
    41       L[i].b=py[i]-L[i].k*px[i];
    42       L[i].pd=1;
    43     }
    44   ans=2e15;
    45   for (i=1;i<n;i++)
    46     {
    47       if (L[i].pd==0) continue;
    48       int T=100;
    49       double l=px[i],r=px[i+1];
    50       double mid1,mid2;
    51       while (T--)
    52     {
    53       mid1=(r-l)/3+l,mid2=r-(r-l)/3;
    54       if (dcmp(cal(mid1,mid1*L[i].k+L[i].b)-cal(mid2,mid2*L[i].k+L[i].b))>=0) l=mid1;
    55       else r=mid2;
    56     }
    57       ans=min(ans,cal(mid1,mid1*L[i].k+L[i].b));
    58     }
    59   printf("%.3lf
    ",ans);
    60 }
    View Code
  • 相关阅读:
    centos搭建window下写的flask程序
    【MTK】iwpriv命令说明
    vs2019专业版离线安装方法
    Python文件编译成exe
    python3升级与安装
    谷歌浏览器https和flash禁用的解决方法
    SQL注入常见函数
    nmap简介与运用
    WPF 万维网对战象棋 客户端+服务端(全套可执行代码在文章末尾)
    《软件工程实践》2020春季学期教学回顾--线上教学,化弊为利
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8280248.html
Copyright © 2011-2022 走看看