【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 

时间: 2024-08-16 18:50:08

【BZOJ1038】【ZJOI2008】瞭望塔 [模拟退火]的相关文章

bzoj千题计划126:bzoj1038: [ZJOI2008]瞭望塔

http://www.lydsy.com/JudgeOnline/problem.php?id=1038 本题可以使用三分法 将点按横坐标排好序后 对于任意相邻两个点连成的线段,瞭望塔的高度 是单峰函数,而且是下凸函数 感性理解单峰就是 瞭望塔建的靠左,为了能看到右边的,要高一点 瞭望塔建的靠右,为了能看到左边的,要高一点 所以 枚举所有线段,三分线段上建造瞭望塔的位置,所有线段上的瞭望塔高度取最小 #include<cmath> #include<cstdio> #include

BZOJ 1038 ZJOI2008 瞭望塔 模拟退火+二分答案

题目大意:给定一条折线,要求选择一个点建立高度为h的瞭望塔,要求瞭望塔塔顶可以看到折线上的每一个点,求h的最小值 正解:半平面交 不会! 于是我们选择模拟退火来寻找瞭望塔的横坐标 确定瞭望塔的高度的时候我们选择二分处理 对于二分的每一个值 我们把折线上的端点从左到右枚举 瞭望塔的塔尖到每个端点的连线必须从左到右逆时针顺序 否则就会被遮挡 如图,塔尖到点2的连线在到点1的连线的顺时针方向,故点1被遮挡,该高度不可行 写完交上去各种秒WA,最后发现我的INF又不够大...我沙茶,我蒟蒻,我这个不长记

【半平面交】bzoj1038 [ZJOI2008]瞭望塔

http://m.blog.csdn.net/blog/qpswwww/44105605 #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define EPS 0.0000001 #define N 311 typedef double db; const db PI=acos(-1.0); struct Point{db x,y;}; typedef Point Ve

BZOJ-1038 [ZJOI2008]瞭望塔

先求半平面交,然后建塔的地方肯定是在半平面交的交点上或者是在地面线段的交点上. #include <cstdlib> #include <cstdio> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #include <cctype> #define rep(i, l, r) for(int i=l; i<=r

[日常摸鱼]bzoj1038[ZJOI2008]瞭望塔-半平面交

这回好好用半平面交写一次- 看了cls当年写的代码看了好久大概看懂了-cls太强辣 #include<cstdio> #include<iostream> #include<algorithm> #define rep(i,n) for(register int i=1;i<=n;i++) #define REP(i,a,b) for(register int i=a;i<=b;i++) #define debug(x) cout<<#x<

【BZOJ1038】[ZJOI2008]瞭望塔 半平面交

[BZOJ1038][ZJOI2008]瞭望塔 Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn.瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置.可见在不同的位置建造瞭望塔,所需要建造的

【BZOJ 1038】 [ZJOI2008]瞭望塔

1038: [ZJOI2008]瞭望塔 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 973  Solved: 428 [Submit][Status] Description 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安.我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), -. (xn, yn)来描述H村的形状,这里x1 < x2 <

1038: [ZJOI2008]瞭望塔

半平面交. 半平面指的就是一条直线的左面(也不知道对不对) 半平面交就是指很多半平面的公共部分. 这道题的解一定在各条直线的半平面交中. 而且瞭望塔只可能在各个点或者半平面交折线的拐点处. 求出半平面交,枚举即可. #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define eps 1e-7 using namespace std; const int maxn

[ZJOI2008]瞭望塔

题目描述 致力于建设全国示范和谐小村庄的H村村长dadzhi,决定在村中建立一个瞭望塔,以此加强村中的治安. 我们将H村抽象为一维的轮廓.如下图所示 我们可以用一条山的上方轮廓折线(x1, y1), (x2, y2), …. (xn, yn)来描述H村的形状,这里x1 < x2 < …< xn.瞭望塔可以建造在[x1, xn]间的任意位置, 但必须满足从瞭望塔的顶端可以看到H村的任意位置.可见在不同的位置建造瞭望塔,所需要建造的高度是不同的.为了节省开支,dadzhi村长希望建造的塔高度