1. 程式人生 > >【BZOJ1038】【ZJOI2008】瞭望塔 [模擬退火]

【BZOJ1038】【ZJOI2008】瞭望塔 [模擬退火]

輪廓 abs none i++ += edi bzoj1038 put continue

瞭望塔

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

【BZOJ1038】【ZJOI2008】瞭望塔 [模擬退火]