半平面交

发布时间 2023-08-19 20:49:17作者: smiling&weeping
Smiling & Weeping
                ---- 那个夏天的蝉鸣比哪一年都聒噪
                 教室外枝桠疯长,却总也挡不住烈阳
 
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2297
 
Talk is cheap , show me the code
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstdio>
 6 #include<vector>
 7 using namespace std;
 8 const double inf = 1e12;
 9 const double pi = acos(-1.0);
10 const double eps = 1e-8;
11 int sgn(double x){
12     if(fabs(x)<eps) return 0;
13     return x<0 ? -1 : 1;
14 }
15 struct Point{
16     double x,y;
17     Point(){}
18     Point(double x,  double y):x(x),y(y){}
19     Point operator + (Point b) {return Point(x+b.x,y+b.y); }
20     Point operator - (Point b) {return Point(x-b.x,y-b.y); }
21     Point operator * (double k) {return Point(x*k,y*k); }
22 };
23 typedef Point Vector;
24 double Cross(Vector A , Vector B){ return A.x*B.y-A.y*B.x; }
25 struct Line{
26     Point p;
27     Vector v;
28     double ang;
29     Line(){}
30     Line(Point p , Vector v):p(p),v(v){ang=atan2(v.y,v.x);}
31     bool operator < (Line &L){return ang<L.ang; } // 用于极角排序
32 };
33 // 点p在线L的左边,即点p在线L的外面
34 bool OnLeft(Line L, Point p){ return sgn(Cross(L.v,p-L.p))>0; }
35 // 两直线交点
36 Point Cross_point(Line a , Line b){
37     Vector 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<Point> HPI(vector<Line> L){
42     int n = L.size();
43     sort(L.begin() , L.end());
44     int first,last;             //指向双端队列的第一个和最后一个元素
45     vector<Point> p(n);         //两个相邻半平面的交点
46     vector<Line> q(n);         //双端队列
47     vector<Point> ans;          //半平面交形成的凸包
48     q[first=last=0] = L[0];
49     for(int i = 1; i < n; i++){
50         // 删除尾部的半平面
51         while(first<last && !OnLeft(L[i] , p[last-1])) last--;
52         // 删除首部的半平面
53         while(first<last && !OnLeft(L[i] , p[first])) first++;
54         q[++last]=L[i];         // 将当前的半平面加入到双端队列中去
55         // 极角相同,保留左边
56         if(fabs(Cross(q[last].v,q[last-1].v))<eps){
57             last--;
58             if(OnLeft(q[last],L[i].p)) q[last]=L[i];
59         }
60         if(first<last) p[last-1]=Cross_point(q[last-1] , q[last]);
61     }
62     // 删除队列中无用的半平面
63     while(first<last && !OnLeft(q[first],p[last-1])) last--;
64     if(last-first<=1) return ans; // 空集
65     p[last] = Cross_point(q[last] , q[first]);
66     for(int i = first; i <= last; i++) ans.push_back(p[i]);
67     return ans;
68 }
69 int main()
70 {
71     int T , n;
72     scanf("%d",&T);
73     while(T--){
74         scanf("%d",&n);
75         vector<Line> L;
76         L.push_back(Line(Point(0,0),Vector(0,-1)));     // 加一个半平面F:反向y轴
77         L.push_back(Line(Point(0,inf),Vector(-1,0)));   // 加一个半平面E:y极大向左的直线
78         while(n--){
79             double a,b;
80             scanf("%lf%lf",&a,&b);
81             L.push_back(Line(Point(0,a) , Vector(1,b)));
82         }
83         vector<Point> ans = HPI(L);
84         printf("%d\n",ans.size()-2); // 去掉人为加入的两个点
85     }
86     return 0;
87 }

少年与爱永不老去,即便披荆斩棘,丢失怒马鲜衣

文章到此结束,我们下次再见