POJ 1113 WALL

        感觉计算几何好难,有些东西做一次理解之后留个模版就好了,不过模版要高度可靠才行,在做凸包时候我们知道极角排序虽然快一点,但是还有一种情况不能解决,当第一条边和最后一条边都存在三点共线的情况的时候是必然矛盾的,当严格要求凸包中的点集的时候就要用水平序了。这道题也要考虑共线的情况但不会有这不会影响求距离。所以还是用Graham Scan和极角排序。

#include<iostream>
#include<algorithm>
#include<cmath>
#define exp 1e-8
#define pi 4*atan(1.0)
using namespace std;
struct Point
{
       double x,y;
} pt[10005];
int n;
double l;
double Dist(Point a,Point b)
{
       return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int Cross(Point a,Point b,Point c)
{
    double t=(b.x-a.x)*(c.y-b.y)-(c.x-b.x)*(b.y-a.y);
    if( fabs(t)<exp)
        return 0;
    return ( t>0?1:-1);
}
bool cmp(const Point&a,const Point&b) //共线的时候选取距离近的。
{
     if( Cross(a,b,pt[0])>0||Cross(a,b,pt[0])==0&&Dist(a,pt[0])<Dist(b,pt[0]))
         return true;
     return false;
}
double Convex()
{
    int i,sp;
    int st[10005];
    st[0]=0; st[1]=1;  sp=1;
    for( i=2; i<=n; i++){
         while( Cross(pt[st[sp]-1],pt[st[sp]],pt[i%n])<0)//逆时针叉乘时如果满足左旋则说明已经拐向。
             sp--;
         st[++sp]=i%n;                              
    }
    double ret=0;
    for( i=0; i<sp; i++)
         ret+=Dist(pt[st[i]],pt[st[i+1]]);
    ret+=2*pi*l;
    return ret;
}
int main()
{
    int i,k;
    scanf("%d%lf",&n,&l);
    for( i=1,k=1; i<=n; i++){   //选取最下,最左的点
         scanf("%lf%lf",&pt[i].x,&pt[i].y);
         if( pt[i].y<pt[k].y||pt[i].y==pt[k].y&&pt[i].x<pt[k].x)
             k=i;
    }
    pt[0]=pt[k]; pt[k]=pt[n];
    sort(pt+1,pt+n,cmp); //极角排序
    printf("%d\n",int(Convex()+0.5)) ;
   // system("pause");
    return 0;
}


你可能感兴趣的:(poj)