zoukankan      html  css  js  c++  java
  • Convex hull凸包

    把一个平面上给出的点都包含进去的最小凸多边形。逆时针输出凸包的各个顶点。

    1.Graham扫描法 (O(n*logn))-------旋转扫除的技术:

    2.Jarvis march步进法(O(n*h))h为凸包的顶点数--------打包的技术

    应用:求二维平面最远点对。

    uva,109

      1 #include <iostream>
      2 #include <vector>
      3 #include <algorithm>
      4 
      5 using namespace std;
      6 
      7 struct node
      8 {
      9     double x,y;
     10     //便于求出初始点
     11     bool operator<(const node& a)const{
     12         return x<a.x || (x==a.x && y<a.y);
     13     }
     14 };
     15 
     16 
     17 typedef vector<node> Vnode;//凸包
     18 typedef vector<Vnode> VVnode;//凸包个数
     19 
     20 //叉积判断是否向左转。
     21 double Isleft(node& p0,node& p1,node& p2)
     22 {
     23     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
     24 }
     25 
     26 //求凸包
     27 int Convex_hull(Vnode p,Vnode &h){
     28     int n=p.size();
     29     int k=0;
     30     //按x升序然后y升序排列
     31     sort(p.begin(),p.end());
     32     
     33     for(int i=0;i<n;i++){
     34 //上链
     35         while(k>=2 && Isleft(h[k-2],h[k-1],p[i])<=0)
     36             k--;
     37         h[k++]=p[i];
     38     }
     39     //下链
     40     for(int i=n-2,t=k+1;i>=0;i--){
     41         while(k>=t && Isleft(h[k-2],h[k-1],p[i])<=0)
     42             k--;
     43         h[k++]=p[i];
     44     }
     45     return k;
     46 }
     47 //检查是否在凸多边形内
     48 int check(Vnode h, node p) {
     49     int n = h.size();
     50     int i, j, c = 0;
     51     for (i = 0, j = n-1; i < n; j = i++)
     52         if ((((h[i].y <= p.y) && (p.y < h[j].y)) || ((h[j].y <= p.y) && (p.y < h[i].y))) && (p.x < (h[j].x - h[i].x) * (p.y - h[i].y) / (h[j].y - h[i].y) + h[i].x))
     53             c = !c;
     54     return c;
     55 }
     56 //根据题意求凸包面积
     57 double Area(Vnode p){
     58     int n=p.size();
     59     double s=0;
     60     
     61     for(int i=1;i<n;i++){
     62         s+=((p[i-1].x*p[i].y-p[i].x*p[i-1].y))/2;
     63     }
     64     return s;
     65 }
     66 
     67 
     68 int main()
     69 {
     70     int n;
     71     VVnode hull;
     72     
     73     while(cin>>n && n!=-1)
     74     {
     75         Vnode p(n);
     76         for(int i=0;i<n;i++)
     77             cin>>p[i].x>>p[i].y;
     78         
     79         Vnode h(n+1);
     80         n=Convex_hull(p,h);
     81         h.resize(n);
     82         hull.push_back(h);
     83     }
     84     
     85     node k;
     86     double a=0;
     87     while(cin>>k.x>>k.y){
     88         VVnode::iterator it;
     89         for(it=hull.begin();it<hull.end();it++)
     90         {
     91             if(check(*it,k))
     92             {
     93                 a+=Area(*it);
     94                 hull.erase(it);
     95                 break;
     96             }
     97         }
     98     }
     99 //输出时带两位小数
    100     cout.precision(2);
    101 //fixed固定格式,floatfield代表以浮点数输出
    102     cout.setf(ios::fixed,ios::floatfield);
    103     cout<<a<<endl;
    104     
    105     return 0;
    106 }
    View Code

    uva,10002

    对于给定点对,求出凸包然后求其重心。

    重心=(每个三角形重心*有向面积)/总面积/3;

    一般三角形以源点(0,0)为起点比较方便。注意三角形重心 ((x1+x2+x3)/3, (y1+y2+y3)/3)

    所以求三角形重心用矢量加法/3则得重心。面积用叉积求/2.

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 const int maxn=105;
     8 const double eps=1e-10;
     9 
    10 struct node
    11 {
    12     double x,y;
    13     node(){}
    14     node(double x,double y):x(x),y(y){}
    15     
    16     bool operator<(const node& p)const{
    17         return x<p.x || (x==p.x && y<p.y);
    18     }
    19     //定义函数简单方便
    20     node operator+(node p){
    21         return node(x+p.x,y+p.y);
    22     }
    23     
    24     node operator-(node p){
    25         return node(x-p.x,y-p.y);
    26     }
    27     
    28     node operator*(double d){
    29         return node(x*d,y*d);
    30     }
    31     
    32     node operator/(double d){
    33         return node(x/d,y/d);
    34     }
    35     
    36     double det(node p){
    37         return x*p.y-y*p.x;
    38     }
    39 }ans[maxn],a[maxn];
    40 
    41 
    42 int n,len;
    43 
    44 void Convex_hull()
    45 {
    46     sort(a,a+n);
    47     len=0;
    48     int i;
    49     for(i=0;i<n;i++)
    50     {
    51         while(len>1 && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--;
    52         ans[len++]=a[i];
    53     }
    54     
    55     int tmp=len;
    56     for(i=n-2;i>=0;--i){
    57         while(len>tmp && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--;
    58         ans[len++]=a[i];
    59     }
    60     --len;
    61 }
    62 //求多边形面积
    63 double Area()
    64 {
    65     double sum=0.0;
    66     
    67     for(int i=0;i<len;i++)
    68         sum+=ans[i].det(ans[i+1]);
    69     return sum/2.0;
    70 }
    71 //求重心
    72 node masscenter()
    73 {
    74     node res=node(0,0);
    75     double s=Area();
    76     if(s<eps) return res;
    77     
    78     for(int i=0;i<len;i++)
    79         res=res+(ans[i]+ans[i+1])*(ans[i].det(ans[i+1]));
    80     return res/s/6.0;
    81 }
    82 
    83 int main()
    84 {
    85     int i;
    86     node res;
    87     while(scanf("%d",&n) && n>=3){
    88         for(i=0;i<n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
    89         
    90         Convex_hull();
    91         res=masscenter();
    92         printf("%.3lf %.3lf
    ",res.x,res.y);
    93     }
    94     return 0;
    95 }
    View Code

    10078

    一开始是想的求点阵的凸包然后比较先后的点数,如果点减少则说明存在凹多边形所以就yes了。

    其实考虑欠周到,还要考虑点是否在凸包里面= =,修正:因为可能他原来就是个凸的,但是有几点共线了。

    p1Xp2为正数说明,p1在p2的顺时针方向。否则在逆时针方向。二分查找到顺时针方向的最近点,然后判断是否在线段的左侧就可以了。附带详解:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cmath>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 const int maxn=55;
      8 const double eps=1e-10;
      9 
     10 struct node
     11 {
     12     double x,y;
     13     node(){}
     14     node(double x,double y):x(x),y(y){}
     15     
     16     bool operator<(const node& p)const{
     17         return x<p.x || (x==p.x && y<p.y);
     18     }
     19     
     20     node operator+(node p){
     21         return node(x+p.x,y+p.y);
     22     }
     23     
     24     node operator-(node p){
     25         return node(x-p.x,y-p.y);
     26     }
     27     
     28     node operator*(double d){
     29         return node(x*d,y*d);
     30     }
     31     
     32     node operator/(double d){
     33         return node(x/d,y/d);
     34     }
     35     
     36     double det(node p){
     37         return x*p.y-y*p.x;
     38     }
     39 }ans[maxn],a[maxn];
     40 
     41 
     42 int n;
     43 
     44 int Convex_hull()
     45 {
     46     if(n<3) return n;
     47     sort(a,a+n);
     48     int len=0;
     49     int i;
     50     for(i=0;i<n;i++)
     51     {
     52         while(len>1 && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--;
     53         ans[len++]=a[i];
     54     }
     55     
     56     int tmp=len;
     57     for(i=n-2;i>=0;--i){
     58         while(len>tmp && (ans[len-1]-ans[len-2]).det(a[i]-ans[len-1])<=eps) len--;
     59         ans[len++]=a[i];
     60     }
     61     return --len;
     62 }
     63 
     64 double cross(node p0, node p1, node p2)
     65 {
     66     return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
     67 }
     68 //二分算法判断是否在凸多边形内。
     69 bool Compl_inside_convex(const node & p,node *con,int n)
     70 {
     71     if(n<3) return false;
     72     if(cross(con[0],p,con[1])>-eps) return false;
     73     if(cross(con[0],p,con[n-1])<eps) return false;
     74     
     75     int i=2,j=n-1;
     76     int line=-1;
     77     
     78     while(i<=j)
     79     {
     80         int mid=(i+j)>>1;
     81         if(cross(con[0],p,con[mid])>-eps)
     82         {
     83             line=mid;
     84             j=mid-1;
     85         }
     86         else i=mid+1;
     87     }
     88     return cross(con[line-1],p,con[line])<-eps;
     89 }
     90 
     91 int main()
     92 {
     93     int i;
     94     node res;
     95     while(scanf("%d",&n),n){
     96         for(i=0;i<n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
     97         
     98         int count=Convex_hull();
     99         int flag=0;
    100         for(int i=0;i<n;i++)
    101 //如果在凸多边形内则原多边形为凹多边形。
    102             if(count>2 && Compl_inside_convex(a[i],ans,count))
    103             {
    104                 flag=1;break;
    105             }
    106         if(flag) printf("Yes
    ");
    107         else printf("No
    ");
    108     }
    109     return 0;
    110 }
    View Code
     1 double cross(cpoint p0, cpoint p1, cpoint p2)
     2 {
     3     return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
     4 }
     5  
     6 bool Compl_inside_convex(const cpoint & p,cpoint *con,int n)
     7 {
     8     if(n<3) return false;
     9     if(cross(con[0],p,con[1])>-eps) return false;
    10     if(cross(con[0],p,con[n-1])<eps) return false;
    11  
    12     int i=2,j=n-1;
    13     int line=-1;
    14  
    15     while(i<=j)
    16     {
    17         int mid=(i+j)>>1;
    18         if(cross(con[0],p,con[mid])>-eps)
    19         {
    20             line=mid;
    21             j=mid-1;
    22         }
    23         else i=mid+1;
    24     }
    25     return cross(con[line-1],p,con[line])<-eps;
    26 }
    判断一个点是否在凸多边形类的二分算法

    uva,681

    注意精度问题,当两者相减的时候考虑极小的精度差,然后就是输入输出。。。见了你的鬼了。。

    我一开始就光顾着把核心东西写出来了。。后面提交了一次才发现还是前面一道题目的条件。然后就wa了一下午。

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cmath>
     4 #include <cstdio>
     5 #include <vector>
     6 #include <cstdlib>
     7 #include <cstring>
     8 
     9 using namespace std;
    10 #define eps 1e-10
    11 
    12 double add(double a,double b)
    13 {
    14     if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;
    15     return a+b;
    16 }
    17 
    18 struct node
    19 {
    20     double x,y;
    21     
    22     node operator-(node p){
    23         return node(add(x,-p.x),add(y,-p.y));
    24     }
    25     
    26     double det(node p){
    27         return add(x*p.y,-y*p.x);
    28     }
    29     
    30     node(){}
    31     node(double x,double y):x(x),y(y){}
    32 };
    33 
    34 bool cmp(const node& a,const node& b)
    35 {
    36     if(fabs(a.y-b.y)>eps)
    37         return a.y<b.y;
    38     return a.x<b.x;
    39 }
    40 
    41 vector<node> convex_hull(vector<node> ps,int n)
    42 {
    43     sort(ps.begin(),ps.end(),cmp);
    44     
    45     int k=0;
    46     vector<node> qs(n*2);
    47     
    48     for(int i=0;i<n;i++){
    49         while(k>1 && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-2])<=0) k--;
    50         qs[k++]=ps[i];
    51     }
    52     
    53     for(int i=n-2,t=k;i>=0;i--){
    54         while(k>t && (qs[k-1]-qs[k-2]).det(ps[i]-qs[k-2])<=0) k--;
    55         qs[k++]=ps[i];
    56     }
    57     qs.resize(k);
    58     return qs;
    59 }
    60 
    61 int main()
    62 {
    63     int tc;
    64     int n;
    65     
    66     int x,y;
    67     vector<node> p;
    68     scanf("%d",&tc);
    69         printf("%d
    ",tc);
    70         while(tc--)
    71         {
    72             p.clear();
    73             scanf("%d",&n);
    74             for(int i=0;i<n;i++)
    75             {
    76                 scanf("%d %d",&x,&y);
    77                 p.push_back(node(x,y));
    78             }
    79             
    80             if(tc) scanf("%d",&x);
    81             
    82             p=convex_hull(p,n);
    83             
    84             printf("%d
    ",(int)p.size());
    85             
    86             for(int i=0;i<(int)p.size();i++)
    87                 printf("%.0lf %.0lf
    ",p[i].x,p[i].y);
    88             
    89             if(tc)
    90                 printf("-1
    ");
    91             
    92         }
    93     return 0;
    94 }
    View Code
    活在现实,做在梦里。
  • 相关阅读:
    466 你真的了解回流和重绘吗
    465 从一道题浅说 JavaScript 的事件循环
    460 动态组件
    458 MongoDB安装
    457 vue d13
    450 for of 循环
    六种排序算法的Js实现
    你真的理解了比较运算符吗?
    5个有趣且不必要的 JavaScipt 技巧
    7个常见的 JavaScript 测验及解答
  • 原文地址:https://www.cnblogs.com/do-it-best/p/5514166.html
Copyright © 2011-2022 走看看