二维凸包求解(Andrew算法 )

Andrew算法是Graham算法的变种。
其主要思想为把凸包上的点依次放入栈中,
如果发现形成了凹多边形(叉积为负值)
就删除一些点,使得又能够维持凸的形态。

这时就会发现,处理各个点需要按照x从左往右的顺序,排序即可
当然,这只是处理了下凸的一个凸壳,倒过来再刷一次,就得到了整个凸包

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

struct point {
    int x,y;
}pt[1005];

int sta[1005], ans[1005], cnt;

int cmp(point a, point b)
{
    //左下角优先,先左后下
    return a.x < b.x || (a.x == b.x && a.y < b.y);
}

int cross(point p0, point p1, point p2)
{
    //大于0,逆时针方向
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}

//Andrew算法
void convex(int n)
{
    sort(pt, pt+n, cmp);
    cnt = 0;
    int top = 0;
    sta[top++] = 0;  //先处理 下凸包
    sta[top++] = 1;
    for(int i = 2; i < n; ++i)
    {
        while(top > 1 && cross(pt[sta[top-2]], pt[sta[top-1]], pt[i]) <= 0)
        {
            top--;
        }
        sta[top++] = i;
    }
    for(int i = 0; i < top; ++i)
    {
        ans[cnt++] = sta[i];
    }

    top = 0;             //求上凸包,并将pt[n-1]与pt[0]连接起来
    sta[top++] = n - 1;
    sta[top++] = n - 2;
    for(int i = n - 3; i >= 0; --i)
    {
        while(top > 1 && cross(pt[sta[top-2]], pt[sta[top-1]], pt[i]) <= 0)
        {
            top--;
        }
        sta[top++] = i;
    }
    for(int i = 0; i < top; ++i)
    {
        ans[cnt++] = sta[i];  //两个凸包的头结点和尾结点存入两次
    }
}

int main()
{
    ifstream in("points.txt");
    if(in)
    {
        string line;
        string data1;
        string data2;
        stringstream input;
        int num = 0;
        int sz;
        bool first = true;
        while(getline(in, line))
        {
            if(first)
            {
               sz = stoi(line);
//               cout << "sz = " << sz << endl;
               first = false;
            } else {
                input.clear();
                input.str(line);
                input >> data1 >> data2;
//                cout << "data1 = " << data1 << endl;
                pt[num].x = stoi(data1);
                pt[num].y = stoi(data2);
                ++num;
            }
        }
        //cout << "num = " << num << endl;  // num == 9

        //计算9个点组成的凸包
        convex(9);

        //输出凸包点的坐标
        for(int i = 0; i < cnt; ++i)
        {
            cout << "x = " << pt[ans[i]].x << "  y = " << pt[ans[i]].y << endl;
        }

    } else {
        cout << "no such file" << endl;
    }


    return 0;
}

/************points.txt*******************
9
1 3
2 7
3 1
4 5
5 4
6 9
7 8
8 2
9 6
******************************************/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值