山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

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

 

【题目链接】

 

    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 }

 

posted on 2016-03-11 16:07  hahalidaxin  阅读(220)  评论(0编辑  收藏  举报