【kuangbin专题】计算几何_凸包

1.poj1113 Wall

题目:http://poj.org/problem?id=1113

题意:用一条线把若干个点包起来,并且线距离任何一个点的距离都不小于r。求这条线的最小距离是多少?

分析:这道题的答案是凸包周长加上一个圆周长,即包围凸包的一个圆角多边形,但是没弄明白那些圆角加起来为什么恰好是一个圆。每个圆角是以凸包对应的顶点为圆心,给定的L为半径,与相邻两条边的切点之间的一段圆弧。每个圆弧的两条半径夹角与对应的凸包的内角互补。假设凸包有n条边,则所有圆弧角之和为180°*n-180°*(n-2)=360°。故,围墙周长为=n条平行于凸包的线段+n条圆弧的长度=凸包周长+围墙离城堡距离L为半径的圆周长。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 using namespace std;
  6 const int maxn=1010;
  7 const double eps=1e-8;
  8 const double pi=acos(-1.0);
  9 inline double sqr(double x){return x*x;}
 10 int sgn(double x){
 11     if (fabs(x)<eps) return 0;
 12     if (x<0) return -1;
 13     return 1;
 14 } 
 15 struct point{
 16     double x,y;
 17     point(){}
 18     point(double _x,double _y):x(_x),y(_y){}
 19     //判断两点相同 
 20     bool operator ==(const point &b) const{  
 21         return sgn(x-b.x)==0 && sgn(y-b.y)==0;
 22     }
 23     // 
 24     point operator -(const point &b) const{
 25         return point(x-b.x,y-b.y);
 26     } 
 27     //叉积 
 28     double operator ^(const point &b) const{
 29         return x*b.y-y*b.x; 
 30     }
 31     //点积
 32     double operator *(const point &b) const{
 33         return x*b.x+y*b.y;
 34     } 
 35     //重载小于号   (求最左下角的点
 36     bool operator <(const point &b)const{
 37         return sgn(x-b.x)==0 ? sgn(y-b.y)<0 : x<b.x;
 38     } 
 39 };
 40 struct line{
 41     point s,e;
 42     line(){}
 43     line(point _s,point _e):s(_s),e(_e){}
 44 };
 45 double dis(point a,point b){
 46     return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
 47 }
 48 struct polygon{
 49     int n;
 50     point p[maxn];
 51     line l[maxn];
 52     void add(point q){
 53         p[n++]=q;
 54     }
 55     void getline(){
 56         for (int i=0;i<n;i++)
 57             l[i]=line(p[i],p[(i+1)%n]);
 58     }
 59     struct cmp{
 60         point p;
 61         cmp(const point &p0):p(p0){}
 62         bool operator ()(const point &aa,const point &bb){
 63             point a=aa,b=bb;
 64             int d=sgn((a-p)^(b-p));
 65             if (d==0){
 66                 return sgn(dis(a,p)-dis(b,p))<0;
 67             }
 68             return d>0;
 69         }
 70     };
 71     //极角排序  先找到左下角的点 
 72     //重载好point的'<' 
 73     void norm(){
 74         point mi=p[0];
 75         for (int i=1;i<n;i++) mi=min(mi,p[i]);
 76         sort(p,p+n,cmp(mi));
 77     } 
 78     //得到凸包,点编号为0--n-1
 79     void Graham(polygon &convex){
 80         norm();
 81         int &top=convex.n;
 82         top=0;
 83         if (n==1){
 84             top=1; convex.p[0]=p[0]; return ;
 85         }
 86         if (n==2){
 87             top=2; convex.p[0]=p[0]; convex.p[1]=p[1];
 88             if (convex.p[0]==convex.p[1]) top--;
 89             return ;
 90         }
 91         convex.p[0]=p[0]; convex.p[1]=p[1]; top=2;
 92         for (int i=2;i<n;i++){
 93             while (top>1 && sgn((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0) top--;
 94             convex.p[top++]=p[i];
 95         }
 96         if (convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
 97     } 
 98 };
 99 polygon C;
100 int main(){
101     int n,L; cin >> n >> L;
102     double x,y;
103     for (int i=0;i<n;i++){
104         cin >> x >> y;
105         C.add(point(x,y));
106     }
107     polygon ans;
108     C.Graham(ans);
109     ans.getline();
110     double res=0;
111     for (int i=0;i<ans.n;i++) res+=dis(ans.l[i].s,ans.l[i].e);
112     res+=2*pi*L;
113     printf("%d
",(int)(res+0.5));
114     return 0;
115 }
poj1113

(为了套板子,写的很繁琐)

2.poj2007 Scrambled Polygon

题目:http://poj.org/problem?id=2007

题意:求一个凸多边形的凸包。要求起始点为输入的第一个点。

分析:rt。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const double eps=1e-8;
 7 const int maxn=55;
 8 inline double sqr(int x){return x*x*1.0;}
 9 int sgn(double x){
10     if (fabs(x)<eps) return 0;
11     if (x<0) return -1;
12     return 1;
13 }
14 struct point{
15     int x,y;
16     point(){}
17     point(int _x,int _y):x(_x),y(_y){}
18     bool operator ==(const point &b)const{
19         return (x==b.x && y==b.y);
20     }
21     point operator -(const point &b)const{
22         return point(x-b.x,y-b.y);
23     }
24     int operator ^(const point &b)const{
25         return x*b.y-y*b.x;
26     }
27     int operator *(const point &b)const{
28         return x*b.x+y*b.y;
29     }
30     //重载小于号   (求最左下角的点
31     bool operator <(const point &b)const{
32         return sgn((x-b.x)*1.0)==0 ? sgn((y-b.y)*1.0)<0 : x<b.x;
33     } 
34 }; 
35 double dis(point a,point b){
36     return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
37 }
38 struct polygon{
39     int n;
40     point p[maxn];
41     void add(point q){
42         p[n++]=q;
43     }
44     struct cmp{
45         point p;
46         cmp(const point &p0):p(p0){}
47         bool operator ()(const point &aa,const point &bb){
48             point a=aa,b=bb;
49             int k=(a-p)^(b-p);int d;
50             if (k==0) d=0;else if (k<0) d=-1; else d=1;
51             if (d==0){
52                 return sgn(dis(a,p)-dis(b,p))<0;
53             }
54             return d>0;
55         }
56     };
57     //极角排序  先找到左下角的点 
58     //重载好point的'<' 
59     void norm(){
60         point mi=p[0];
61         for (int i=1;i<n;i++) mi=min(mi,p[i]);
62         sort(p,p+n,cmp(mi));
63     } 
64     //得到凸包,点编号为0--n-1
65     void Graham(polygon &convex){
66         norm();
67         int &top=convex.n;
68         top=0;
69         if (n==1){
70             top=1; convex.p[0]=p[0]; return ;
71         }
72         if (n==2){
73             top=2; convex.p[0]=p[0]; convex.p[1]=p[1];
74             if (convex.p[0]==convex.p[1]) top--;
75             return ;
76         }
77         convex.p[0]=p[0]; convex.p[1]=p[1]; top=2;
78         for (int i=2;i<n;i++){
79             while (top>1 && sgn(((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))*1.0)<=0) top--;
80             convex.p[top++]=p[i];
81         }
82         if (convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
83     } 
84 };
85 polygon C;
86 int main(){
87     int x,y; point p;
88     C.n=0; 
89     cin >> x >> y; p=point(x,y); C.add(p);
90     while (cin >> x >> y) C.add(point(x,y));
91     polygon ans;
92     C.Graham(ans); int k;
93     for (int i=0;i<ans.n;i++) if (ans.p[i]==p){k=i;break;}
94     for (int i=0;i<ans.n;i++){
95         printf("(%d,%d)
",ans.p[(k+i)%ans.n].x,ans.p[(k+i)%ans.n].y);
96     }
97     return 0;
98 }
poj2007

3.poj1228

  题目:http://poj.org/problem?id=1228

题意:输入一个凸包上的点(没有凸包内部的点,要么是凸包顶点,要么是凸包边上的点),判断这个凸包是否稳定。所谓稳定就是判断能不能在原有凸包上加点。

分析:问凸包是否稳定。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 const double eps=1e-8;
 7 const int maxn=1010;
 8 int sgn(double x){
 9     if (fabs(x)<eps) return 0;
10     if (x<0) return -1;
11     return 1;
12 }
13 struct point{
14     double x,y;
15     point(){}
16     point(double _x,double _y):x(_x),y(_y){}
17     point operator -(const point &b)const{
18         return point(x-b.x,y-b.y);
19     }
20     double operator ^(const point &b)const{
21         return x*b.y-y*b.x;
22     }
23 }p[maxn],pp[maxn]; 
24 bool cmp(point a,point b) {return a.x < b.x || (a.x == b.x && a.y < b.y);}
25 int convexhull(point p[],int n,point pp[]){
26     sort(p,p+n,cmp);
27     int m=0;
28     for (int i=0;i<n;i++){
29         while (m>1 && ((pp[m-1]-pp[m-2])^(p[i]-pp[m-2]))<0) m--;
30         pp[m++]=p[i];
31     } 
32     int k=m;
33     for (int i=n-2;i>=0;i--){
34         while (m>k && ((pp[m-1]-pp[m-2])^(p[i]-pp[m-2]))<0) m--;
35         pp[m++]=p[i];
36     }
37     return m-1;
38 }
39 bool check(point p[],int n){
40     for (int i=1;i<n-2;i++){
41         if (((p[i-1]-p[i])^(p[i+1]-p[i]))!=0 &&
42             ((p[i]-p[i+1])^(p[i+2]-p[i+1]))!=0) return false;  //保证至少有三个点在同一条边上 
43     } 
44     return true;
45 }
46 int main(){
47     int t,n; double x,y; cin >> t;
48     while (t--){
49         cin >> n;
50         for (int i=0;i<n;i++) cin >> p[i].x >> p[i].y;
51         if (n<6){cout << "NO
";continue;}
52         int cnt=convexhull(p,n,pp);
53         if (check(pp,cnt)) cout << "YES
"; else cout << "NO
";
54     }
55     return 0;
56 }
poj1228

4

5.poj3348 Cows

题目:http://poj.org/problem?id=3348

题意:给出一些点圈出一个最大面积每50平方养一头牛问最多能养多少牛。

分析:凸包+多边形面积。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 using namespace std;
  6 const int maxn=10005;
  7 inline int sqr(int x){return x*x;}
  8 struct point{
  9     int x,y;
 10     point(){}
 11     point(int _x,int _y):x(_x),y(_y){}
 12     //判断两点相同 
 13     bool operator ==(const point &b) const{  
 14         return x-b.x==0 && y-b.y==0;
 15     }
 16     // 
 17     point operator -(const point &b) const{
 18         return point(x-b.x,y-b.y);
 19     } 
 20     //叉积 
 21     int operator ^(const point &b) const{
 22         return x*b.y-y*b.x; 
 23     }
 24     //点积
 25     int operator *(const point &b) const{
 26         return x*b.x+y*b.y;
 27     } 
 28     //重载小于号   (求最左下角的点
 29     bool operator <(const point &b)const{
 30         return x-b.x==0?y-b.y<0:x<b.x;
 31     } 
 32 };
 33 struct line{
 34     point s,e;
 35     line(){}
 36     line(point _s,point _e):s(_s),e(_e){}
 37 };
 38 int dis(point a,point b){
 39     return (int)sqrt(1.0*sqr(a.x-b.x)+1.0*sqr(a.y-b.y));
 40 }
 41 struct polygon{
 42     int n;
 43     point p[maxn];
 44     void add(point q){p[n++]=q;}
 45     struct cmp{
 46         point p;
 47         cmp(const point &p0):p(p0){}
 48         bool operator ()(const point &aa,const point &bb){
 49             point a=aa,b=bb;
 50             int k=(a-p)^(b-p);
 51             if (k==0){
 52                 return dis(a,p)-dis(b,p)<0;
 53             }
 54             return k>0;
 55         }
 56     };
 57     //极角排序  先找到左下角的点 
 58     //重载好point的'<' 
 59     void norm(){
 60         point mi=p[0];
 61         for (int i=1;i<n;i++) mi=min(mi,p[i]);
 62         sort(p,p+n,cmp(mi));
 63     } 
 64     //得到凸包,点编号为0--n-1
 65     void Graham(polygon &convex){
 66         norm();
 67         int &top=convex.n;
 68         top=0;
 69         if (n==1){
 70             top=1; convex.p[0]=p[0]; return ;
 71         }
 72         if (n==2){
 73             top=2; convex.p[0]=p[0]; convex.p[1]=p[1];
 74             if (convex.p[0]==convex.p[1]) top--;
 75             return ;
 76         }
 77         convex.p[0]=p[0]; convex.p[1]=p[1]; top=2;
 78         for (int i=2;i<n;i++){
 79             while (top>1 && ((convex.p[top-1]-convex.p[top-2])^(p[i]-convex.p[top-2]))<=0) top--;
 80             convex.p[top++]=p[i];
 81         }
 82         if (convex.n==2 && (convex.p[0]==convex.p[1])) convex.n--;
 83     } 
 84     int getarea(){
 85         int sum=0;
 86         for (int i=0;i<n;i++) sum+=(p[i]^(p[(i+1)%n]));
 87         return sum/2;
 88     }
 89 };
 90 polygon C;
 91 int main(){
 92     int n,x,y; cin >> n; C.n=0;
 93     for (int i=0;i<n;i++){
 94         cin >> x >> y;
 95         C.add(point(x,y));
 96     }
 97     polygon ans; C.Graham(ans);
 98     cout << ans.getarea()/50 << endl;
 99     return 0;
100 }
poj3348

 6.poj1259/hdoj6219

题意:给出n个点,求出最大面积的凸包且凸包内不包含原点集中的点。

分析:rt。求最大面积空凸包。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 const double eps=1e-8;
 7 const int maxn=1005; 
 8 inline double sqr(double x){return x*x;}
 9 int sgn(double x){
10     if (fabs(x)<eps) return 0;
11     if (x<0) return -1;
12     return 1;
13 } 
14 struct point{
15     double x,y;
16     point(){}
17     point(double _x,double _y):x(_x),y(_y){}
18     //判断两点相同 
19     bool operator ==(const point &b) const{  
20         return sgn(x-b.x)==0 && sgn(y-b.y)==0;
21     }
22     // 
23     point operator -(const point &b) const{
24         return point(x-b.x,y-b.y);
25     } 
26     //叉积 
27     double operator ^(const point &b) const{
28         return x*b.y-y*b.x; 
29     }
30     //点积
31     double operator *(const point &b) const{
32         return x*b.x+y*b.y;
33     } 
34     //重载小于号   (求最左下角的点
35     bool operator <(const point &b)const{
36         return sgn(x-b.x)==0 ? sgn(y-b.y)<0 : x<b.x;
37     } 
38 }p[maxn],pp[maxn];
39 point tmp;
40 double dp[maxn][maxn];
41 double empty_convex(point p[],int n,point o){
42     double ans=0;
43     for (int i=0;i<n;i++) for (int j=0;j<n;j++) dp[i][j]=0;
44     for (int i=0;i<n;i++){
45         int j=i-1;
46         while (j>=0 && ((p[i]-o)^(p[j]-o))==0) j--;
47         bool flag=(j==i-1);
48         while (j>=0){
49             int k=j-1;
50             while (k>=0 && ((p[i]-p[k])^(p[j]-p[k]))>0) k--;
51             double area=fabs((p[i]-o)^(p[j]-o))/2.0;
52             if (k>=0) area+=dp[j][k];
53             if (flag) dp[i][j]=area;
54             ans=max(ans,area);
55             j=k;
56         }
57         if (flag){
58             for (int j=1;j<i;j++) dp[i][j]=max(dp[i][j],dp[i][j-1]);
59         }
60     }
61     return ans;
62 }
63 double dist(point a,point b){
64     return sqrt((a-b)*(a-b));
65 }
66 bool cmp_angle(point a,point b){
67     double res=(a-tmp)^(b-tmp);
68     if (res) return res>0;
69     return dist(a,tmp)<dist(b,tmp);
70 }
71 double largest_empty_convex(point p[],int n){
72     double ans=0;
73     for (int i=0;i<n;i++){
74         tmp=p[i];
75         int cnt=0;
76         for (int j=0;j<n;j++){
77             if (p[j].y>tmp.y || p[j].y==tmp.y && p[j].x>tmp.x) pp[cnt++]=p[j];
78         }
79         sort(pp,pp+cnt,cmp_angle);  //根据极角排序
80         ans=max(ans,empty_convex(pp,cnt,tmp)); 
81     }
82     return ans;
83 }
84 int main(){
85     int t,n; cin >> t;
86     while (t--){
87         cin >> n;
88         for (int i=0;i<n;i++) cin >> p[i].x >> p[i].y;
89         double ans=largest_empty_convex(p,n);
90         printf("%.1f
",ans);
91     }
92     return 0;
93 } 
poj1259
原文地址:https://www.cnblogs.com/changer-qyz/p/9770115.html