zoukankan      html  css  js  c++  java
  • 【BZOJ1038】【ZJOI2008】瞭望塔 [模拟退火]

    瞭望塔

    Time Limit: 10 Sec  Memory Limit: 162 MB
    [Submit][Status][Discuss]

    Description

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

      我们将H村抽象为一维的轮廓。如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn。

      瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置。

      可见在不同的位置建造瞭望塔,所需要建造的高度是不同的。

      为了节省开支,dadzhi村长希望建造的塔高度尽可能小。请你写一个程序,帮助dadzhi村长计算塔的最小高度。

    Input

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

    Output

      仅包含一个实数,为塔的最小高度,精确到小数点后三位。

    Sample Input

      4
      10 20 49 59
      0 10 10 0

    Sample Output

      14.500

    HINT

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

    Solution

      首先,如果我们确定了一个点的话,显然是可以Check的。

      对于 每一个点连向这个点连线 必须是要逆时针方向的。

      那么如果有一个横坐标了,我们就可以二分答案了。怎么确定这个横坐标呢?

      乍一看,数据这么小:当然是模拟退火啦!上一波退火美滋滋。٩(๑>◡<๑)۶

    Code

      1 #include<iostream>    
      2 #include<string>    
      3 #include<algorithm>    
      4 #include<cstdio>    
      5 #include<cstring>    
      6 #include<cstdlib>
      7 #include<cmath>
      8 #include<queue>
      9 using namespace std;  
     10 typedef unsigned long long s64;
     11  
     12 const int ONE = 1005;
     13 const double eps = 1e-4;
     14  
     15 int n;
     16 double from, to;
     17 double Ans = 1e20;
     18  
     19 struct power
     20 {
     21         double x, y;
     22 }a[ONE];
     23  
     24 int get()
     25 {
     26         int res,Q=1;    char c;
     27         while( (c=getchar())<48 || c>57)
     28         if(c=='-')Q=-1;
     29         if(Q) res=c-48; 
     30         while((c=getchar())>=48 && c<=57) 
     31         res=res*10+c-48; 
     32         return res*Q; 
     33 }
     34  
     35 int PD(double a, double b)
     36 {
     37         if(fabs(a - b) <= eps) return 0;
     38         if(a > b) return 1;
     39         return -1;
     40 }
     41  
     42 double Gety(double x)
     43 {
     44         for(int i = 2; i <= n; i++)
     45             if(PD(a[i-1].x, x) <= 0 && PD(x, a[i].x) <= 0)
     46             {
     47                 double k = (a[i].y - a[i-1].y) / (a[i].x - a[i-1].x);
     48                 double b = a[i-1].y;
     49                 return k * (x - a[i-1].x) + b;
     50             }
     51 }
     52  
     53 double Cross(power a, power b, power c) {return (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);}
     54 int Check(power A)
     55 {
     56         for(int i = 2; i <= n; i++)
     57             if(PD(Cross(a[i-1], a[i], A), 0) < 0) return 0;
     58         return 1;
     59 }
     60  
     61 double Judge(double x)
     62 {
     63         double l = 0, r = 1e10, res;
     64         double y = Gety(x);
     65         while(l < r - 0.0001)
     66         {
     67             double mid = (l + r) / 2;
     68             if(Check( (power){x, y + mid} )) r = mid;
     69             else l = mid;
     70         }
     71         if(Check( (power){x, y + l} )) res = l; else res = r;
     72         Ans = min(Ans, res);
     73         return res;
     74 }
     75  
     76 double Random() {return (rand()%1000) / 1000.00;}
     77 void SA(double T)
     78 {
     79         double Now = (from + to) / 2, A;
     80         Judge(Now);
     81         while(T >= 0.0001)
     82         {
     83             A = Now + T * (Random() * 2 - 1);
     84             if(!(from <= A && A <= to)) continue;
     85             double dE = Judge(Now) - Judge(A);
     86             if(dE > 0 || Random() <= exp(dE / T))
     87                 Now = A;
     88             T *= 0.993;
     89         }
     90          
     91         for(double i = -1; i <= 1; i += 0.001)
     92             Judge(Now + i);
     93 }
     94  
     95 int main()
     96 {
     97         n = get();
     98         for(int i = 1; i <= n; i++) scanf("%lf", &a[i].x);
     99         for(int i = 1; i <= n; i++) scanf("%lf", &a[i].y);
    100          
    101          
    102         from = a[1].x;  to = a[n].x;
    103         SA(to - from);
    104          
    105         printf("%.3lf", Ans);
    106 }
    107 
    View Code
  • 相关阅读:
    最长公共子序列问题LCS
    [LuoguP2900] [USACO08MAR]土地征用(Land Acquisition)
    [LuoguP3195] [HNOI2008]玩具装箱TOY
    $Yeasion$的码风修改历程
    点分治模板
    Poj2919 Crane
    Poj2010 Moo University
    Kuhn-Munkres算法
    Uva10791 Minimum Sum LCM
    P1018 乘积最大(高精度加/乘)
  • 原文地址:https://www.cnblogs.com/BearChild/p/7286623.html
Copyright © 2011-2022 走看看