zoukankan      html  css  js  c++  java
  • poj1113 凸包

    result=对所有点凸包周长+pi*2*L

    WA了一次,被Pi的精度坑了

    以后注意Pi尽可能搞精确一点。Pi=3.14还是不够用

    Code:

      1 #include<vector>
      2 #include<list>
      3 #include<map>
      4 #include<set>
      5 #include<deque>
      6 #include<queue>
      7 #include<stack>
      8 #include<bitset>
      9 #include<algorithm>
     10 #include<functional>
     11 #include<numeric>
     12 #include<utility>
     13 #include<iostream>
     14 #include<sstream>
     15 #include<iomanip>
     16 #include<cstdio>
     17 #include<cmath>
     18 #include<cstdlib>
     19 #include<cctype>
     20 #include<string>
     21 #include<cstring>
     22 #include<cstdio>
     23 #include<cmath>
     24 #include<cstdlib>
     25 #include<ctime>
     26 #include<climits>
     27 #include<complex>
     28 #define mp make_pair
     29 #define pb push_back
     30 using namespace std;
     31 const double eps=1e-8;//精度
     32 const double pi=acos(-1.0);//π
     33 const double inf=1e20;//无穷大
     34 const int maxp=1111;//最大点数
     35 
     36 /*
     37     判断d是否在精度内等于0
     38 */
     39 int dblcmp(double d)
     40 {
     41     if (fabs(d)<eps)return 0;
     42     return d>eps?1:-1;
     43 }
     44 /*
     45     求x的平方
     46 */
     47 inline double sqr(double x){return x*x;}
     48 /*
     49     点/向量
     50 */
     51 struct point
     52 {
     53     double x,y;
     54     point(){}
     55     point(double _x,double _y):x(_x),y(_y){};
     56     //读入一个点
     57     void input()
     58     {
     59         scanf("%lf%lf",&x,&y);
     60     }
     61     //输出一个点
     62     void output()
     63     {
     64         printf("%.2f %.2f
    ",x,y);
     65     }
     66     //判断两点是否相等
     67     bool operator==(point a)const
     68     {
     69         return dblcmp(a.x-x)==0&&dblcmp(a.y-y)==0;
     70     }
     71     //判断两点大小
     72     bool operator<(point a)const
     73     {
     74         return dblcmp(a.x-x)==0?dblcmp(y-a.y)<0:x<a.x;
     75     }
     76     //点到源点的距离/向量的长度
     77     double len()
     78     {
     79         return hypot(x,y);
     80     }
     81     //点到源点距离的平方
     82     double len2()
     83     {
     84         return x*x+y*y;
     85     }
     86     //两点间的距离
     87     double distance(point p)
     88     {
     89         return hypot(x-p.x,y-p.y);
     90     }
     91     //向量加
     92     point add(point p)
     93     {
     94         return point(x+p.x,y+p.y);
     95     }
     96     //向量减
     97     point sub(point p)
     98     {
     99         return point(x-p.x,y-p.y);
    100     }
    101     //向量乘
    102     point mul(double b)
    103     {
    104         return point(x*b,y*b);
    105     }
    106     //向量除
    107     point div(double b)
    108     {
    109         return point(x/b,y/b);
    110     }
    111     //点乘
    112     double dot(point p)
    113     {
    114         return x*p.x+y*p.y;
    115     }
    116     //叉乘
    117     double det(point p)
    118     {
    119         return x*p.y-y*p.x;
    120     }
    121     //XXXXXXX
    122     double rad(point a,point b)
    123     {
    124         point p=*this;
    125         return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p))));
    126     }
    127     //截取长度r
    128     point trunc(double r)
    129     {
    130         double l=len();
    131         if (!dblcmp(l))return *this;
    132         r/=l;
    133         return point(x*r,y*r);
    134     }
    135     //左转90度
    136     point rotleft()
    137     {
    138         return point(-y,x);
    139     }
    140     //右转90度
    141     point rotright()
    142     {
    143         return point(y,-x);
    144     }
    145     //绕点p逆时针旋转angle角度
    146     point rotate(point p,double angle)
    147     {
    148         point v=this->sub(p);
    149         double c=cos(angle),s=sin(angle);
    150         return point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
    151     }
    152 };
    153 /*
    154     线段/直线
    155 */
    156 struct line
    157 {
    158     point a,b;
    159     line(){}
    160     line(point _a,point _b)
    161     {
    162         a=_a;
    163         b=_b;
    164     }
    165     //判断线段相等
    166     bool operator==(line v)
    167     {
    168         return (a==v.a)&&(b==v.b);
    169     }
    170     //点p做倾斜角为angle的射线
    171     line(point p,double angle)
    172     {
    173         a=p;
    174         if (dblcmp(angle-pi/2)==0)
    175         {
    176             b=a.add(point(0,1));
    177         }
    178         else
    179         {
    180             b=a.add(point(1,tan(angle)));
    181         }
    182     }
    183     //直线一般式ax+by+c=0
    184     line(double _a,double _b,double _c)
    185     {
    186         if (dblcmp(_a)==0)
    187         {
    188             a=point(0,-_c/_b);
    189             b=point(1,-_c/_b);
    190         }
    191         else if (dblcmp(_b)==0)
    192         {
    193             a=point(-_c/_a,0);
    194             b=point(-_c/_a,1);
    195         }
    196         else
    197         {
    198             a=point(0,-_c/_b);
    199             b=point(1,(-_c-_a)/_b);
    200         }
    201     }
    202     //读入一个线段
    203     void input()
    204     {
    205         a.input();
    206         b.input();
    207     }
    208     //校准线段两点
    209     void adjust()
    210     {
    211         if (b<a)swap(a,b);
    212     }
    213     //线段长度
    214     double length()
    215     {
    216         return a.distance(b);
    217     }
    218     //直线倾斜角 0<=angle<180
    219     double angle()
    220     {
    221         double k=atan2(b.y-a.y,b.x-a.x);
    222         if (dblcmp(k)<0)k+=pi;
    223         if (dblcmp(k-pi)==0)k-=pi;
    224         return k;
    225     }
    226     //点和线段关系
    227     //1 在逆时针
    228     //2 在顺时针
    229     //3 平行
    230     int relation(point p)
    231     {
    232         int c=dblcmp(p.sub(a).det(b.sub(a)));
    233         if (c<0)return 1;
    234         if (c>0)return 2;
    235         return 3;
    236     }
    237     //点是否在线段上
    238     bool pointonseg(point p)
    239     {
    240         return dblcmp(p.sub(a).det(b.sub(a)))==0&&dblcmp(p.sub(a).dot(p.sub(b)))<=0;
    241     }
    242     //两线是否平行
    243     bool parallel(line v)
    244     {
    245         return dblcmp(b.sub(a).det(v.b.sub(v.a)))==0;
    246     }
    247     //线段和线段关系
    248     //0 不相交
    249     //1 非规范相交
    250     //2 规范相交
    251     int segcrossseg(line v)
    252     {
    253         int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
    254         int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
    255         int d3=dblcmp(v.b.sub(v.a).det(a.sub(v.a)));
    256         int d4=dblcmp(v.b.sub(v.a).det(b.sub(v.a)));
    257         if ((d1^d2)==-2&&(d3^d4)==-2)return 2;
    258         return (d1==0&&dblcmp(v.a.sub(a).dot(v.a.sub(b)))<=0||
    259                 d2==0&&dblcmp(v.b.sub(a).dot(v.b.sub(b)))<=0||
    260                 d3==0&&dblcmp(a.sub(v.a).dot(a.sub(v.b)))<=0||
    261                 d4==0&&dblcmp(b.sub(v.a).dot(b.sub(v.b)))<=0);
    262     }
    263     //线段和直线v关系
    264     int linecrossseg(line v)//*this seg v line
    265     {
    266         int d1=dblcmp(b.sub(a).det(v.a.sub(a)));
    267         int d2=dblcmp(b.sub(a).det(v.b.sub(a)));
    268         if ((d1^d2)==-2)return 2;
    269         return (d1==0||d2==0);
    270     }
    271     //直线和直线关系
    272     //0 平行
    273     //1 重合
    274     //2 相交
    275     int linecrossline(line v)
    276     {
    277         if ((*this).parallel(v))
    278         {
    279             return v.relation(a)==3;
    280         }
    281         return 2;
    282     }
    283     //求两线交点
    284     point crosspoint(line v)
    285     {
    286         double a1=v.b.sub(v.a).det(a.sub(v.a));
    287         double a2=v.b.sub(v.a).det(b.sub(v.a));
    288         return point((a.x*a2-b.x*a1)/(a2-a1),(a.y*a2-b.y*a1)/(a2-a1));
    289     }
    290     //点p到直线的距离
    291     double dispointtoline(point p)
    292     {
    293         return fabs(p.sub(a).det(b.sub(a)))/length();
    294     }
    295     //点p到线段的距离
    296     double dispointtoseg(point p)
    297     {
    298         if (dblcmp(p.sub(b).dot(a.sub(b)))<0||dblcmp(p.sub(a).dot(b.sub(a)))<0)
    299         {
    300             return min(p.distance(a),p.distance(b));
    301         }
    302         return dispointtoline(p);
    303     }
    304     //XXXXXXXX
    305     point lineprog(point p)
    306     {
    307         return a.add(b.sub(a).mul(b.sub(a).dot(p.sub(a))/b.sub(a).len2()));
    308     }
    309     //点p关于直线的对称点
    310     point symmetrypoint(point p)
    311     {
    312         point q=lineprog(p);
    313         return point(2*q.x-p.x,2*q.y-p.y);
    314     }
    315 };
    316 
    317 /*
    318     多边形
    319 */
    320 struct polygon
    321 {
    322     int n;//点个数
    323     point p[maxp];//顶点
    324     //读入一个多边形
    325     void input(int n)
    326     {
    327         for (int i=0;i<n;i++)
    328         {
    329             p[i].input();
    330         }
    331     }
    332     struct cmp
    333     {
    334         point p;
    335         cmp(const point &p0){p=p0;}
    336         bool operator()(const point &aa,const point &bb)
    337         {
    338             point a=aa,b=bb;
    339             int d=dblcmp(a.sub(p).det(b.sub(p)));
    340             if (d==0)
    341             {
    342                 return dblcmp(a.distance(p)-b.distance(p))<0;
    343             }
    344             return d>0;
    345         }
    346     };
    347     void norm()
    348     {
    349         point mi=p[0];
    350         for (int i=1;i<n;i++)mi=min(mi,p[i]);
    351         sort(p,p+n,cmp(mi));
    352     }
    353     //求凸包存入多边形convex
    354     void getconvex(polygon &convex)
    355     {
    356         int i,j,k;
    357         sort(p,p+n);
    358         convex.n=n;
    359         for (i=0;i<min(n,2);i++)
    360         {
    361             convex.p[i]=p[i];
    362         }
    363         if (n<=2)return;
    364         int &top=convex.n;
    365         top=1;
    366         for (i=2;i<n;i++)
    367         {
    368             while (top&&convex.p[top].sub(p[i]).det(convex.p[top-1].sub(p[i]))<=0)
    369                 top--;
    370             convex.p[++top]=p[i];
    371         }
    372         int temp=top;
    373         convex.p[++top]=p[n-2];
    374         for (i=n-3;i>=0;i--)
    375         {
    376             while (top!=temp&&convex.p[top].sub(p[i]).det(convex.p[top-1].sub(p[i]))<=0)
    377                 top--;
    378             convex.p[++top]=p[i];
    379         }
    380     }
    381     //取得周长
    382     double getcircumference()
    383     {
    384         double sm=0;
    385         int i;
    386         for (i=0;i<n;i++)
    387         {
    388             sm+=p[i].distance(p[(i+1)%n]);
    389             //printf("%.2f
    ",sm);
    390         }
    391         return sm;
    392     }
    393 };
    394 
    395 struct polygon P,R;
    396 int N,L;
    397 double sum=0;
    398 
    399 int main()
    400 {
    401     //freopen("in2.txt","r",stdin);
    402 
    403     cin>>N>>L;
    404     P.n=N;
    405     P.input(N);
    406     P.getconvex(R);
    407 
    408     sum=R.getcircumference();
    409     //cout<<R.n<<endl;
    410     //for (int i=0;i<R.n;i++)
    411     //    printf("%.2f %.2f
    ",R.p[i].x,R.p[i].y);
    412 
    413     sum+=3.14159265358979723846*(double)L*2;
    414     printf("%.0f
    ",sum);
    415 
    416     return 0;
    417 }
    View Code

    最基础的凸包算法:卷包裹算法。基本思想就好像把所有的点比作一堆钉子,拿一根绳子捆在最左边的点上,然后按顺时针or逆时针围一圈

    http://www.cnblogs.com/Booble/archive/2011/02/28/1967179.html

    ------------------------我是傲傲傲娇哒分割线---------------------------------

    求凸包的Andrew算法:

    设所有点在平面坐标系上,从最左下角的点开始,从左到右来一次,再从右到左来一次,最后回到起点。

    把所有点按x和y坐标作为关键字从小到大排序(x优先)。先把第一个点和第二个点加入凸包。

    在扫描的过程中,当前凸包的前进方向即倒数第二个入凸包的点->倒数第一个入凸包的点这一向量。

    若新点在凸包前进方向的左边则继续,否则依次删除最近加入凸包的点,直到新点在左边为止。

    eg:

    STEP1:当前已经加入了这些点:

    STEP2:加入了点4

    STEP3:这时再想加5的时候发现5在向量3->4的右边,加不了了-_-||

         于是把4删掉。

    STEP4:这时5在向量2->3的左边了。加5

        PS:如果删掉了还是在右边的话就接着删

    判断新点在某个向量的左边还是右边可以用叉乘。

  • 相关阅读:
    图片延时加载LazyLoad真的是LazyLoad吗?
    IO流操作实现文件拷贝\简单加密及相关知识点
    浅谈WebService开发(一)
    一次网站被挂恶意代码的查错经历
    自测,我的优点与缺点
    共鸣,此话在中国的确有些道理
    VsAddIn "Region this"
    虹影图片下载器(Preview)
    Group != Team
    同感,不转不行 低调做人,高调做事
  • 原文地址:https://www.cnblogs.com/pdev/p/4236735.html
Copyright © 2011-2022 走看看