凸包 極角排序

const int maxn=1005;
const double eps=1e-10;

struct point{
    int x;
    int y;
    point(){} 
    point(int xx,int yy):x(xx),y(yy){}
    bool friend operator <(const point &a,const point &b){
        if(a.x==b.x) return a.y<b.y;
        return a.x<b.x;
    }
    bool friend operator ==(const point &a,const point &b){
        return a.x==b.x&&a.y==b.y;
    }
    bool friend operator !=(const point &a,const point &b){
        return !(a==b);
    }
    point friend operator -(const point &a,const point &b){
        return point(a.x-b.x,a.y-b.y);
    }
}p[maxn],O,q[2*maxn+10];//p:原本的點集   O:中心點   q:凸包裏的點集 

bool cmp(point a,point b)//順時針極角排序 
{
    return a.x*b.y>a.y*b.x;
}

double cross2(point a,point b,point c)
{
    return (c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x);
}

bool cmp1(point p2,point p3)//以O爲中心,極角排序 
{
    return cross2(O,p2,p3)<eps;
}
double cross(point a,point b){//叉乘 
    return a.x*b.y-b.x*a.y;
}
double dis(point a,point b){//兩點間的距離 
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}


int PointOffLine( point pt, point start, point end)
{
	//判斷點point與線段(start,end)的關係
 
//返回值:>0 點在矢量start,end的逆時針方向
 
//       =0 點在線段(start,end)或其延長線上
 
//       <0 點在矢量start,end的順時針方向
 
    return ((pt.x - end.x)*(start.y - end.y)-(start.x - end.x)*(pt.y - end.y));
}

int n,m;
double Andrew(){//無序求凸包 
    sort(p,p+n);
    m=0;
    for(int i=0;i<n;i++){
        while(m>1&&cross(q[m-1]-q[m-2],p[i]-q[m-2])<=0) m--; 
        //等號決定共線的點是否進入棧,也就是是否要凸邊上的點
        q[m++]=p[i];     
    } 
    int o=m;
    for(int i=n-2;i>=0;i--){
        while(m>o&&cross(q[m-1]-q[m-2],p[i]-q[m-2])<=0) m--;
        //等號決定共線的點是否進入棧,也就是是否要凸邊上的點
        q[m++]=p[i];
    }
    if(n>1) m--;
   	double ans=0;
    for(int i=1;i<m;i++){
        ans+=dis(q[i],q[i-1]);
    }
    return ans+dis(q[0],q[m-1]);
}

double Melkman(){//有序快速求凸包 
    int head,tail;
     head=tail=n;
    q[tail++]=p[0];

    int i;
    for(i=0;i<n-1;i++){
        q[tail]=p[i];

        if(cross(p[i]-q[head],p[i+1]-q[head])) break;
    }
    if(n==1) return 0;
    if(n==2) return dis(p[0],p[1]);
    if(n==3){
        return dis(p[0],p[1])+dis(p[0],p[2])+dis(p[1],p[2]);
    } 
    q[--head]=q[++tail]=p[++i];
    if(cross(q[n+1]-q[n],q[n+2]-q[n])<0) swap(q[n],q[n+1]);
    for(++i;i<n;i++){

       if(cross(q[tail]-q[tail-1],p[i]-q[tail-1])>0
        &&cross(q[head]-q[head+1],p[i]-q[head+1])<0) continue; //凹凸全部滿足,這個點是內部點,不考慮
      while(tail-head>1&&cross(q[tail]-q[tail-1],p[i]-q[tail-1])<=0)  tail--;
      q[++tail]=p[i];
      while(tail-head>1&&cross(q[head]-q[head+1],p[i]-q[head+1])>=0)  head++;
      q[--head]=p[i];

    }
    double ans=0;
    for(int i=head;i<tail;i++){
        ans+=dis(q[i],q[i+1]);
    }
    return ans;

}

double Area()//凸包求面積 
{
   if(m<3)return 0;
   int i;
    double ret=0.0;
    for(i=2; i<m; i++)
    {
        ret+=fabs(cross2(q[0],q[i-1],q[i])/2.0);
    }
     return ret;
}

double RC(int len){  //len 指凸包點集合長度 vic[] 凸包點 cross 叉積 同上
    int t=1;
    double ans=dis(p[0],p[1]);
    for(int i=0;i<len;i++){

        while(abs(cross(p[(i+1)%len]-p[i],p[t]-p[i]))
           <abs(cross(p[(i+1)%len]-p[i],p[(t+1)%len]-p[i])))
          t=(t+1)%len;
          ans=max(ans,max(dis(p[t],p[i]),dis(p[(i+1)%len],p[t])));

    }
    return ans;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章