Convex Hull:O(n^4)算法

课程:计算几何
书籍:计算几何:算法与应用

极点:构成凸包的顶点,它具有这样的性质:经过该点,总能找到一条直线,使得其他所有点都在该直线的同一侧。

根据该思路,极点不会处于其他顶点所构成的三角形内部。因此我们只需要所有点进行它是否在其他顶点所组成的三角形内部做判断,即可得出所有的极点。

如何判断一个点是否在三角形内:按逆时针方向去看三角形的边,如果一个点在三角形内部,则该点总在三角形所有边的左侧。因此我们只需要做三此点是否在边的左侧的判断即可。

如何判断一个点是否在一条向量的左侧:根据两个向量叉乘的符号去判断。S为判断点,AB为向量,如果AB × AS > 0 则 点S在向量AB的左侧;如果AB × AS = 0 点S在直线AB上;如果AB × AS < 0 则 点S在向量AB的右侧。


代码:

Point.h

#pragma once
#ifndef POINT_H
#define POINT_H

#include<iostream>
using namespace std;

class Point {
public:
    int index;
    float x, y;
    bool isExtremePoint;

public:
    Point() { index = 0; x = y = 0.0f; isExtremePoint = false; }
    ~Point() {}

    Point(int index, float xx, float yy) {
        this->index = index;
        x = xx; y = yy;
    }

    Point(Point &temp) :index(temp.index), x(temp.x), y(temp.y), isExtremePoint(temp.isExtremePoint){}


    friend ostream& operator<<(ostream& os, Point& temp) {
        os << "Point index: " << temp.index << " (x,y): " << temp.x << "," << temp.y << endl;
        return os;
    }
};

#endif // !POINT_H

Main.cpp

/*  indere 2018/6/22
*   O(n^4)构造凸包算法思路为:如果一个点不在其他点所组成的三角形内部,则该点是极点
*   输入:顶点数以及顶点坐标
*   输出:极点编号(看情况是否按Counter-Clockwise输出)
/

/*  输入:
    10
    7 9
    -8 -1
    -3 -1
    1 4
    -3 9
    6 -4
    7 5
    6 6
    -6 10
    0 8
*/


#include "Point.h"

Point *points;
int pointsize;

void Initialize();                              //初始化points数组
void ConstructConvexHull(Point* points);        //根据Point数组信息 构造凸包
bool InTriangle(int p1, int p2, int p3, int s); //判断点s是否在p1,p2,p3做组成的三角形内
int  ToLeft(int v1, int v2, int s);             //ToLeft Test

int main() {

    Initialize();
    ConstructConvexHull(points);


    for (int i = 0; i < pointsize; i++) {
        if (points[i].isExtremePoint)
            cout << points[i];
    }

    return 0;
}

void Initialize() {
    cin >> pointsize;
    points = new Point[pointsize];
    for (int i = 0; i < pointsize; i++) {
        float x, y;
        cin >> x >> y;
        points[i] = Point(i + 1, x, y);
    }
}

void ConstructConvexHull(Point* points) {

    for (int i = 0; i < pointsize; i++)
        points[i].isExtremePoint = true;


    for (int i = 0; i < pointsize; i++) {
        for (int j = i + 1; j < pointsize; j++) {
            for (int k = j + 1; k < pointsize; k++) {
                for (int s = 0; s < pointsize; s++) {
                    if (s != i && s != j && s != k && InTriangle(i, j, k, s)) {         //如果s点在i,j,k所组成的三角形中,则s为非极点  
                        points[s].isExtremePoint = false;
                    }
                }
            }
        }
    }
}

bool InTriangle(int p1, int p2, int p3, int s) {


    bool result = false;
    int t1 = ToLeft(p1, p2, s);
    int t2 = ToLeft(p2, p3, s);
    int t3 = ToLeft(p3, p1, s);
    if (t1 == t2 && t2 == t3 && t3 == t1 && t1 != 2)    //最后一个判断是为了判断 这几个点不共线
        result = true;
    return result;
}

int  ToLeft(int v1, int v2, int s) {
    float result = (points[v2].x * points[s].y + points[v1].x * points[v2].y + points[v1].y * points[s].x)
                 - (points[v1].y * points[v2].x + points[v1].x * points[s].y + points[v2].y * points[s].x);

    if (result > 0.0f)      //左侧
        return 1;
    if (result == 0.0f)     //共线
        return 2;
    if (result < 0.0f)      //右侧
        return -1;
}

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值