[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\n",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\n",ans); 60 } View Code?
轉載于:https://www.cnblogs.com/Y-E-T-I/p/8280248.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的[ZJOI2008]瞭望塔的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二分图常用建图方法及其性质
- 下一篇: WEB跨域问题