ACM -- 凸包问题

1. 凸(凹)多边形

创业是需要地盘的,HDU向钱江肉丝高新技术开发区申请一块用地,很快得到了批复,据说这是因为他们公司研发的“海东牌”老鼠药科技含量很高,预期将占全球一半以上的市场。政府划拨的这块用地是一个多边形,为了描述它,我们用逆时针方向的顶点序列来表示,我们很想了解这块地的基本情况,现在请你编程判断HDU的用地是凸多边形还是凹多边形呢?

Input

输入包含多组测试数据,每组数据占2行,首先一行是一个整数n,表示多边形顶点的个数,然后一行是2×n个整数,表示逆时针顺序的n个顶点的坐标(xi,yi),n为0的时候结束输入。

 

Output

对于每个测试实例,如果地块的形状为凸多边形,请输出“convex”,否则输出”concave”,每个实例的输出占一行。

 

Sample Input

4

0 0 1 0 1 1 0 1

0

 

Sample Output

convex


两种思路:

一种是百度过来的,使用向量的叉乘

按照输入顺序依次将点连接起来,对于联系的三个点p0,p1,p2,令向量a=p1-p0,b=p2-p1

若是凸多边形,那么b相对于a一定是向逆时针方向旋转的 判断两向量的旋转方向,可以使用向量的茶积a×b = x1 × y2 - x2 × y1 ,

当a×b> 0时,b在a的逆时针方向

当a×b = 0 时,b与a平行

当a×b < 0 时,b在a的顺时针方向

要注意的是最后一个点pn,还要跟起始的两个点p0,p1判断一次。

#include "stdio.h"

typedef struct  
{
	int x, y;
}Point;

int det(int x1, int y1, int x2, int y2)
{
	return x1*y2 - x2*y1;
}

int corss(Point p0, Point p1, Point p2){
	return det(p1.x - p0.x, p1.y - p0.y, p2.x - p1.x, p2.y - p1.y);
}

void getP(Point *p){
	scanf("%d%d", &(p->x), &(p->y));
}

int main()
{
    int i,j,k,m,n;
    int s,flag;
    Point p0,q0,p,q,r;
    
    while(scanf("%d",&n),n){
        if(n<3){
            for(i=0;i<n;i++) scanf("%*d%*d");
            puts("convex");
            continue;
        }
        
        flag=1;
        getP(&p0); getP(&q0);
        r=p0; p=q0;
        
        for(i=2;i<n;i++){
            getP(&q);
            if(corss(r,p,q)<0) flag=0;
            r=p; p=q;
        }
        
        if(corss(r,p,p0)<0) flag=0;
        if(corss(p,p0,q0)<0) flag=0;
        
        if(flag) puts("convex");
        else puts("concave");
    }
    return 0;
}


第二种自己的思路,思路来源于算法上的分治法

在很多情况下,顺序将点输入到电脑需要我们人工自己先进行排列,我就想,在混乱的情况下将各个点进行判断,使用分治法

用一个存储空间将全部的点存起来,然后在进行分析

分析如下:

1. 先找出所有点集合的最左边的点跟最右边的点,用一条直线将两个点连接,这样子就将整体的点分成了两个部分,一般来说,会分成上下两部分

2. 然后分别找到上下两个部分的最高点跟最低点,这样就可以与上面的两个点形成两个三角形,当我们只要判断在三角形中是否这样上半部分的点就被分成三部分了(如下图),最左边的一部分,最右边一部分,还有包含在中间的一部分

3. 当到这个情况下的时候,我们就可以判断了,如果在三角形中间存在点,我们就可以得知这个多边形是凹包,直接返回
4. 要是没有发现,递归如上步骤,直到没有发现点就说明这个是凸包


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值