二维凸包模板(凸包重心,周长,面积,直径,最大三角形,最小环绕矩形)

#include"string.h"
#include"stdio.h"
#include"iostream"
#include"algorithm"
#include"queue"
#include"stack"
#define M 100009
#define N 100009
#include"stdlib.h"
#include"math.h"
#define inf 10000000000000000LL
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define eps 1e-10
using namespace std;
struct node
{
    double x,y;
    node(){}
    node(double _x,double _y):x(_x),y(_y){}
    node operator +(node p)//向量加法
    {
        return node(x+p.x,y+p.y);
    }
    node operator -(node p)//向量减法
    {
        return node(x-p.x,y-p.y);
    }
    double operator *(node p)//向量叉乘
    {
        return x*p.y-y*p.x;
    }
    double operator ^(node p)//向量点乘
    {
        return x*p.x+y*p.y;
    }
    node operator /(double p)//向量除法
    {
        return node(x/p,y/p);
    }
    node operator *(double p)//向量乘法
    {
        return node(x*p,y*p);
    }
}p[M],q[M];
int cnt,n;
double max(double x,double y)
{
    return x>y?x:y;
}
double min(double x,double y)
{
    return x<y?x:y;
}
double cross(node a,node b,node c)//叉积
{
    return (b-a)*(c-a);
}
double dot(node a,node b,node c)//点积
{
    return (b-a)^(c-a);
}
double len(node a)//向量长吨
{
    return sqrt(a^a);
}
double dis(node a,node b)//两点距离
{
    return len(b-a);
}
int cmp(node a,node b)//极角排序
{
    double temp=cross(p[0],a,b);//逆时针排序
    if(temp>0)
        return 1;
    else if(fabs(temp)<eps&&dis(p[0],a)<dis(p[0],b))//角度相同则按照距离排序
        return 1;
    else
        return 0;
}
void input(int n)//输入
{
    for(int i=0;i<n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
}
void sort_point(int n)//凸包点集的输入即排序
{
    int i,k;
    node start;
    start=p[0];
    k=0;
    for(i=1;i<n;i++)
    {
        if((start.y>p[i].y)||(fabs(start.y-p[i].y)<eps&&start.x>p[i].x))
        {
            start=p[i];
            k=i;
        }
    }
    p[k]=p[0];
    p[0]=start;
    sort(p+1,p+n,cmp);
}
void be_weight(int val)
{
    int temp=val;
    n=1;
    for(int i=1;i<temp;i++)
    {
        if(fabs(p[i-1].x-p[i].x)<eps&&fabs(p[i-1].y-p[i].y)<eps)
            continue;
        p[n++]=p[i];
    }
}
void Convex_hull(int n)//求凸包凸包上的点存在q中
{
    int i;
    if(n==1)
    {
        q[0]=p[0];
        cnt=1;
    }
    else if(n==2)
    {
        q[0]=p[0];
        q[1]=p[1];
        q[2]=p[0];
        cnt=2;
    }
    else if(n>=3)
    {
        q[0]=p[n-1];
        q[1]=p[0];
        q[2]=p[1];
        cnt=2;
        for(i=2;i<n;i++)
        {
            while(cross(q[cnt-1],q[cnt],p[i])<0)
                cnt--;
            q[++cnt]=p[i];
        }
    }
}
double Perimeter(int cnt)//凸包周长
{
    double sum=0;
    for(int i=1;i<=cnt;i++)
        sum+=dis(q[i-1],q[i]);
    return sum;
}
double Area(int cnt)//凸包面积
{
    double sum=0;
    node p(0,0);
    for(int i=1;i<=cnt;i++)
        sum+=cross(p,q[i-1],q[i]);
    return fabs(sum/2.0);
}
node barycenter_cur(int n)//原多边形的重心
{
    double sum=0;
    node ret(0.0,0.0);
    for(int i=2;i<n;i++)
    {
        double area=cross(p[0],p[i-1],p[i]);
        sum+=area;
        ret=ret+(p[0]+p[i-1]+p[i])/3.0*area;
    }
    ret=ret/sum;
    return ret;
}
node barycenter_now(int cnt)//凸包的重心
{
    double sum=0;
    node ret(0.0,0.0);
    for(int i=2;i<cnt;i++)
    {
        double area=cross(q[0],q[i-1],q[i]);
        sum+=area;
        ret=ret+(q[0]+q[i-1]+q[i])/3.0*area;
    }
    ret=ret/sum;
    return ret;
}
double Diameter(int cnt)//旋转卡壳法求凸包的直径即最大的点对距离
{
    double maxi=0;
    int j=1;
    for(int i=1;i<=cnt;i++)
    {
        while(fabs(cross(q[i-1],q[i],q[(j+1)%cnt]))>fabs(cross(q[i-1],q[i],q[j%cnt])))
            j++;
        maxi=max(maxi,dis(q[i-1],q[j%cnt]));
        maxi=max(maxi,dis(q[i],q[j%cnt]));
    }
    return maxi;
}
double Max_triangle(int cnt)//旋转卡壳法求面积最大的三角形
{
    double maxi=0;
    int j=1;
    int k=1;
    for(int i=1;i<=cnt;i++)
    {
        while(fabs(cross(q[i-1],q[j%cnt],q[(k+1)%cnt]))>fabs(cross(q[i-1],q[j%cnt],q[k%cnt])))
            k++;
        maxi=max(maxi,fabs(cross(q[i-1],q[j%cnt],q[k%cnt])));
        while(fabs(cross(q[i-1],q[(j+1)%cnt],q[k%cnt]))>fabs(cross(q[i-1],q[j%cnt],q[k%cnt])))
            j++;
        maxi=max(maxi,fabs(cross(q[i-1],q[j%cnt],q[k%cnt])));
    }
    return maxi/2.0;
    /*其思路是这样的,定点I,p,q,先I,p固定,让q旋转找到最大的面积三角形,之后,I,q固定,p旋转,
        找到最大的三角形面积,比较记录.然后i++;直到i遍历所有顶点.所求出来的三角形就是面积
        最大.这里的旋转卡壳思想就是固定,旋转.这样的.显然i++后,p,q两点不需要再从i+1,i+2开始,这
        个好形容,对p,q进行取模运算的时候,注意自己的SP栈指针多大.*/
}
void Min_rectangle(int cnt)//旋转卡壳法求面积和周长最小的环绕矩形
{
    if(cnt<=2)//输出时注意的地方*****
    {
        if(cnt==1)
            printf("%.2lf %.2lf\n",0.0,0.0);
        else
            printf("%.2lf %.2lf\n",0.0,2*dis(p[0],p[1]));
        return;
    }
    double S=inf,C=inf;
    int j,k,r;
    double h,w;
    j=k=r=1;
    for(int i=1;i<=cnt;i++)
    {
        double L=dis(q[i-1],q[i]);
        while(fabs(cross(q[i-1],q[i],q[(j+1)%cnt]))>fabs(cross(q[i-1],q[i],q[j%cnt])))
            j++;
        h=fabs(cross(q[i-1],q[i],q[j%cnt]))/L;
        while(dot(q[i-1],q[i],q[(k+1)%cnt])>dot(q[i-1],q[i],q[k%cnt]))
            k++;
        if(i==1)
            r=k;
        while(dot(q[i-1],q[i],q[(r+1)%cnt])<=dot(q[i-1],q[i],q[r%cnt]))
            r++;
        w=(dot(q[i-1],q[i],q[k%cnt])-dot(q[i-1],q[i],q[r%cnt]))/L;
        S=min(S,w*h);
        C=min(C,(w+h)*2);
    }
    printf("%.2lf ",S);//输出时注意的地方*****
    printf("%.2lf\n",C);
}
int main()
{
    while(scanf("%d",&n),n)
    {
        input(n);//输入
        sort_point(n);//极角排序
        be_weight(n);//去重
        Convex_hull(n);//求凸包
        Min_rectangle(cnt);
    }
    return 0;
}

posted @ 2014-10-14 14:05  一样菜  阅读(814)  评论(0编辑  收藏  举报