CGL_4_A——Convex Hull 求凸包

题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_A

题目给出一个多边形,要求出这个多边形的凸包;

在一个点集D中,按一定顺序选取子集Q
使得Q中所有点顺次连接所构成的封闭凸多边形包住D中所有点

可以形象地理解为:有许多个钉子钉在平面上,用一根牛皮筋把所有点包住

找出凸包的思路是:

先把题目给出的多边形的点集合按x坐标从小到大排序,x相同的按y从小到大排序;(点的<前面已经重载过,符合这个要求)

将排序后的集合遍历,先把2个放入栈u中,如果新加入一个点后,能保证u中的点仍然是凸包的,就加进去,否则就pop出来一个点,直到u成为一个凸包为止;这样就得到了凸包的上半部分;
再把点按照x从大到小排序,x相同的y从大到小排序;
其他的操作同上,由此得到凸包的下半部分。
最后,把上下两部分合并(按照要求,本题是要求逆时针方向输出生成凸包中的点)

坑点:输出的时候以凸多边形最下端最左侧的顶点为起点,按逆时针方向依次输出坐标

//求凸包,时间复杂度nlogn
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;

const int maxn=100005;

int n,tot;//n为点的个数,tot为凸点的个数
struct point
{
    double x,y;
};
point p[maxn],CHP[maxn];//CHP为凸包最后所构成的点

bool cmp(point a,point b)//水平排序,按x从大到小排,如果x相同,按y从大到小排序
{
    return (a.x<b.x||(a.x==b.x&&a.y<b.y));
}

double xmul(point a,point b,point c)//叉积
{
    return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

int cmpp(point A, point B)     ///x从小到大,y从小到大                
{
	return (A.y<B.y || (A.y == B.y&&A.x<B.x));
}

void Andrew()   ///模板
{
    sort(p,p+n,cmp);
    tot=0;

    for(int i=0; i<n; ++i) //计算下半个凸包
    {
        while(tot>1&&xmul(CHP[tot-2],CHP[tot-1],p[i])<0)
            --tot;
        CHP[tot++]=p[i];
    }

    int k=tot;
    for(int i=n-2; i>=0; --i) //计算上半个凸包
    {
        while(tot>k&&xmul(CHP[tot-2],CHP[tot-1],p[i])<0)
            --tot;
        CHP[tot++]=p[i];
    }

    if(n>1)//对于只有一个点的包再单独判断
        --tot;
}

point q[maxn];
int main()
{
    scanf("%d",&n);
    for(int i=0; i<n; ++i)
    {
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    Andrew();
     int index;
     sort(p,p+tot,cmp);  ///将CHP复制到q数组中
     for(int i=0; i<tot; ++i)
     {
         q[i].x=CHP[i].x;
         q[i].y=CHP[i].y;
     }
   sort(q,q+tot,cmpp);  ///将q排序,将左下角的坐标放在q【0】.
   for(int i=0;i<tot;i++)
   {
       if((q[0].x==CHP[i].x)&&(q[0].y==CHP[i].y))
       {
           index=i; ///找到左下角下标
       }
   }
    printf("%d\n",tot);
    for(int i=0; i<tot; ++i)
    {
        printf("%d %d\n",(int)CHP[(i+index)%tot].x,(int)CHP[(i+index)%tot].y);///将左下角的坐标作为第一个
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值