[BZOJ1038][ZJOI2008]瞭望塔(半平面交)

1038: [ZJOI2008]瞭望塔

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2999  Solved: 1227
[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

【输入样例一】
6
1 2 4 5 6 7
1 2 2 4 2 1
【输入样例二】
4
10 20 49 59
0 10 10 0

Sample Output

【输出样例一】
1.000
【输出样例二】
14.500

HINT

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

Source

[Submit][Status][Discuss]

这题做的真是。。心力交瘁。。其实就是一个半平面交,然而我发现自己实际上完全不会这个东西。

据说模拟退火和三分都可以做,但是考虑将每条边的上半部分求交,最后这个凸包上的点和原折线的这点才可能是答案。

证明应该是分段一次函数的极致只可能出现在端点上。

剩下的就是一系列半平面交模板的问题了,写了一个先将两点式转成点斜式直线方程再求交的函数,WA,发现点斜式根本不能处理与y轴平行的直线。

然后又看了以前模板中的定比分点叉积求交的函数,WA,发现这个只能求线段交点。

https://blog.csdn.net/u013050857/article/details/40923789

最后极不情愿地写了将式子化到底的做法,感觉这个函数根本背不下来。

不过幸好发现了这个问题,否则考场上要是写了就会很惨。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 typedef double db;
 6 using namespace std;
 7 
 8 const int N=1010;
 9 const double eps=1e-8;
10 int n,tot,cnt;
11 db ans=1e60;
12 struct P{ db x,y; }p[N],a[N];
13 struct L{ P a,b; db sl; }l[N],q[N],tmp[N];
14 
15 double dmult(P a,P b,P c){ return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); }
16 bool operator <(const L &a,const L &b){ return (a.sl!=b.sl) ? a.sl<b.sl : dmult(a.a,a.b,b.b)<-eps; }
17 
18 P inter(L a,L b){
19     double A1=a.b.y-a.a.y,B1=a.a.x-a.b.x,C1=-B1*a.a.y-A1*a.a.x;
20     double A2=b.b.y-b.a.y,B2=b.a.x-b.b.x,C2=-B2*b.a.y-A2*b.a.x;
21     return (P){(C1*B2-C2*B1)/(B1*A2-B2*A1),(C1*A2-C2*A1)/(A1*B2-A2*B1)};
22 }
23 bool jud(L a,L b,L c){ P t=inter(a,b); return dmult(c.a,c.b,t)<-eps; }
24 
25 void work(){
26     tmp[++tot]=l[1];
27     rep(i,2,cnt) if (fabs(l[i].sl-l[i-1].sl)>eps) tmp[++tot]=l[i];
28     rep(i,1,tot) l[i]=tmp[i];
29     int L=1,R=0; q[++R]=l[1]; q[++R]=l[2];
30     rep(i,3,tot){
31         while (L<R && jud(q[R-1],q[R],l[i])) R--;
32         while (L<R && jud(q[L+1],q[L],l[i])) L++;
33         q[++R]=l[i];
34     }
35     while (L<R && jud(q[R-1],q[R],q[L])) R--;
36     while (L<R && jud(q[L+1],q[L],q[R])) L++;
37     tot=0; rep(i,L,R-1) p[++tot]=inter(q[i],q[i+1]);
38 }
39 
40 void getans(){
41     rep(k,1,tot)
42         rep(i,1,n-1){
43             P t=(P){p[k].x,-1};
44             if (p[k].x>=a[i].x && p[k].x<=a[i+1].x)
45                 ans=min(ans,p[k].y-inter((L){a[i],a[i+1]},(L){t,p[k]}).y);
46         }
47     rep(k,1,n)
48         rep(i,1,tot-1){
49             P t=(P){a[k].x,-1};
50             if (a[k].x>=p[i].x && a[k].x<=p[i+1].x)
51                 ans=min(ans,inter((L){p[i],p[i+1]},(L){t,a[k]}).y-a[k].y);
52         }
53 }
54 
55 int main(){
56     scanf("%d",&n);
57     rep(i,1,n) scanf("%lf",&a[i].x);
58     rep(i,1,n) scanf("%lf",&a[i].y);
59     a[0]=(P){a[1].x,100000}; a[n+1]=(P){a[n].x,100000};
60     rep(i,0,n) l[++cnt]=(L){a[i],a[i+1],atan2(a[i+1].y-a[i].y,a[i+1].x-a[i].x)};
61     sort(l+1,l+cnt+1); work(); getans(); printf("%.3lf
",ans);
62     return 0;
63 }
View Code

UPD:感觉自己十分愚蠢,与y轴平行的直线判一下不就好了。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 #define A double k2=(b.b.y-b.a.y)/(b.b.x-b.a.x),b2=b.a.y-k2*b.a.x
 6 #define B double k1=(a.b.y-a.a.y)/(a.b.x-a.a.x),b1=a.a.y-k1*a.a.x
 7 typedef double db;
 8 using namespace std;
 9 
10 const int N=1010;
11 const double eps=1e-8;
12 int n,tot,cnt;
13 db ans=1e60;
14 struct P{ db x,y; }p[N],a[N];
15 struct L{ P a,b; db sl; }l[N],q[N],tmp[N];
16 
17 double dmult(P a,P b,P c){ return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); }
18 bool operator <(const L &a,const L &b){ return (a.sl!=b.sl) ? a.sl<b.sl : dmult(a.a,a.b,b.b)<-eps; }
19 
20 P inter(L a,L b){
21     if (a.a.x==a.b.x){ A; return (P){a.a.x,k2*a.a.x+b2}; }
22     if (b.a.x==b.b.x){ B; return (P){b.a.x,k1*b.a.x+b1}; }
23     A; B; double x=(b2-b1)/(k1-k2),y=k1*x+b1;
24     return (P){x,y};
25 }
26 
27 bool jud(L a,L b,L c){ P t=inter(a,b); return dmult(c.a,c.b,t)<-eps; }
28 
29 void work(){
30     tmp[++tot]=l[1];
31     rep(i,2,cnt) if (fabs(l[i].sl-l[i-1].sl)>eps) tmp[++tot]=l[i];
32     rep(i,1,tot) l[i]=tmp[i];
33     int L=1,R=0; q[++R]=l[1]; q[++R]=l[2];
34     rep(i,3,tot){
35         while (L<R && jud(q[R-1],q[R],l[i])) R--;
36         while (L<R && jud(q[L+1],q[L],l[i])) L++;
37         q[++R]=l[i];
38     }
39     while (L<R && jud(q[R-1],q[R],q[L])) R--;
40     while (L<R && jud(q[L+1],q[L],q[R])) L++;
41     tot=0; rep(i,L,R-1) p[++tot]=inter(q[i],q[i+1]);
42 }
43 
44 void getans(){
45     rep(k,1,tot)
46         rep(i,1,n-1){
47             P t=(P){p[k].x,-1};
48             if (p[k].x>=a[i].x && p[k].x<=a[i+1].x)
49                 ans=min(ans,p[k].y-inter((L){a[i],a[i+1]},(L){t,p[k]}).y);
50         }
51     rep(k,1,n)
52         rep(i,1,tot-1){
53             P t=(P){a[k].x,-1};
54             if (a[k].x>=p[i].x && a[k].x<=p[i+1].x)
55                 ans=min(ans,inter((L){p[i],p[i+1]},(L){t,a[k]}).y-a[k].y);
56         }
57 }
58 
59 int main(){
60     freopen("tower.in","r",stdin);
61     freopen("tower.out","w",stdout);
62     scanf("%d",&n);
63     rep(i,1,n) scanf("%lf",&a[i].x);
64     rep(i,1,n) scanf("%lf",&a[i].y);
65     a[0]=(P){a[1].x,100000}; a[n+1]=(P){a[n].x,100000};
66     rep(i,0,n) l[++cnt]=(L){a[i],a[i+1],atan2(a[i+1].y-a[i].y,a[i+1].x-a[i].x)};
67     sort(l+1,l+cnt+1); work(); getans(); printf("%.3lf
",ans);
68     return 0;
69 }
View Code
原文地址:https://www.cnblogs.com/HocRiser/p/8974434.html