【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=1038
【题意】
找一个最低塔高使可以看到村庄的每一个角落。
【思路】
半平面交
能够看到一个线段的点都在该线段所在直线的上方,如果能看到所有的线段则该区域就是所有线段所在直线的半平面交。
最低塔高就是要求这个区域与村庄之间的最短距离。无论是交还是村庄都可以看作是分段的一次函数,所以最近距离一定在分段点处取得。分别枚举交和村庄的分段点即可。
需要注意的有:预先添加两个边界。求最近距离时先判断一下x的关系,否则谁知道交点飞到哪去T_T
【代码】
1 #include<cmath> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 using namespace std; 8 9 const int N = 305; 10 const double bond = 100001; 11 const double eps = 1e-10; 12 13 struct Pt { 14 double x,y; 15 Pt (double x=0,double y=0):x(x),y(y){} 16 }; 17 typedef Pt vec; 18 19 vec operator + (Pt a,Pt b) { return vec(a.x+b.x,a.y+b.y); } 20 vec operator - (Pt a,Pt b) { return vec(a.x-b.x,a.y-b.y); } 21 vec operator * (Pt a,double p) { return vec(a.x*p,a.y*p); } 22 23 double cross(Pt a,Pt b) { return a.x*b.y-a.y*b.x; } 24 25 struct Line { 26 Pt p; vec v; double ang; 27 Line () {} 28 Line (Pt p,vec v) :p(p),v(v){ ang=atan2(v.y,v.x); } 29 bool operator < (const Line& rhs) const { 30 return ang<rhs.ang; 31 } 32 }; 33 34 bool onleft(Line L,Pt p) { return cross(L.v,p-L.p)>0; } 35 Pt LineInter(Line a,Line b) 36 { 37 vec u=a.p-b.p; 38 double t=cross(b.v,u)/cross(a.v,b.v); 39 return a.p+a.v*t; 40 } 41 vector<Pt> HPI(vector<Line> L) 42 { 43 int n=L.size(); 44 sort(L.begin(),L.end()); 45 int f,r; 46 vector<Pt> p(n) , ans; 47 vector<Line> q(n); 48 q[f=r=0]=L[0]; 49 for(int i=1;i<n;i++) { 50 while(f<r&&!onleft(L[i],p[r-1])) r--; 51 while(f<r&&!onleft(L[i],p[f])) f++; 52 q[++r]=L[i]; 53 if(fabs(cross(q[r].v,q[r-1].v))<eps) { 54 r--; 55 if(onleft(q[r],L[i].p)) q[r]=L[i]; 56 } 57 if(f<r) p[r-1]=LineInter(q[r-1],q[r]); 58 } 59 while(f<r&&!onleft(q[f],p[r-1])) r--; 60 if(r-f<=1) return ans; 61 p[r]=LineInter(q[r],q[f]); 62 for(int i=f;i<=r;i++) ans.push_back(p[i]); 63 return ans; 64 } 65 66 vector<Line> L; 67 vector<Pt> p,np; 68 int n; 69 70 int main() 71 { 72 scanf("%d",&n); 73 double x[N],y[N]; 74 for(int i=1;i<=n;i++) { 75 scanf("%lf",&x[i]); 76 } 77 for(int i=1;i<=n;i++) { 78 scanf("%lf",&y[i]); 79 } 80 p.push_back(Pt(x[1],y[1]+1)); 81 for(int i=1;i<=n;i++) p.push_back(Pt(x[i],y[i])); 82 p.push_back(Pt(x[n],y[n]+1)); 83 for(int i=0;i<=n;i++) { 84 L.push_back(Line(p[i],p[i+1]-p[i])); 85 } 86 np=HPI(L); 87 double ans=1e30; 88 for(int i=0;i<np.size();i++) 89 for(int j=1;j<=n;j++) if(np[i].x>=p[j].x&&np[i].x<=p[j+1].x) { 90 Pt x=Pt(np[i].x,-1); 91 x=LineInter(Line(p[j],p[j+1]-p[j]),Line(x,np[i]-x)); 92 ans=min(ans,np[i].y-x.y); 93 } 94 for(int i=1;i<=n;i++) 95 for(int j=0;j<(int)np.size()-1;j++) if(p[i].x>=np[j].x&&p[i].x<=np[j+1].x) { 96 Pt x=Pt(p[i].x,-1); 97 x=LineInter(Line(np[j],np[j+1]-np[j]),Line(x,p[i]-x)); 98 ans=min(ans,x.y-p[i].y); 99 } 100 printf("%.3lf",ans); 101 return 0; 102 }