求凸包(我太菜了)

今天学弟问到了…就稍稍写一下吧,似乎是叫(Graham扫描法)?
(只会这一个) 太菜了

其实求凸包很简单 (为什么当时就是学不会?被自己菜哭)
首先要找到左下角的点.(它一定是凸包上的点)
以那个点为中心极角排序
然后把排完序的前两个点入栈
判断栈中倒数第二个点与最后一个点和当前判断的点构成向量的叉乘,如果为负值,退栈,一直退到不为负值或者栈中的元素树小于2
把正在判断的点入栈

等到所有点遍历完了,栈中的元素就是凸包上的点…

代码如下:(实在没有什么值得多说的…)

#include <iostream>
#include <algorithm>
#define MAX 1000
using namespace std;

struct node {
    int x, y;

    node(int _x = 0, int _y = 0)
    {
        x = _x;
        y = _y;
    }

    node operator -(node a)//向量减
    {
        return node(x - a.x, y - a.y);
    }

    int operator*(node a)//叉乘
    {
        return (x * a.y - y * a.x);
    }

    friend int getdis(node a, node b)//两点间距离的平方
    {
        return ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }

    void show()
    {
        cout << "x:" << x << " y:" << y << endl;
    }

}p[MAX];

int ans[MAX];
int n;

int cmp(node a, node b)//极角排序
{
    int t = (a - p[0]) * (b - p[0]);
    if (t != 0)
        return t > 0;
    else
        return getdis(a, p[0]) < getdis(b, p[0]);
}

void getans()
{
    int len = 0;
    ans[len++] = 0;
    for (int i = 1; i < n; i++)
    {
        while (len >= 2 && ((p[ans[len - 1]] - p[ans[len - 2]]) * (p[i] - p[ans[len - 2]]) <= 0)) len--;
        ans[len++] = i;
    }//求凸包...
    for (int i = 0; i < len; i++)
        p[ans[i]].show();
    int s = 0;
    for (int i = 1; i+1 < len; i++)
    {
        s += (p[ans[i]] - p[0]) * (p[ans[i + 1]] - p[0]);
    }//求凸多边形面积(因为我这里都是整数,就没用double...正常写肯定要用double的...)
    cout << 1.0 * s / 2;
}


int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> p[i].x >> p[i].y;
    int m = 0;//最左下的点的下标
    for (int i = 1; i < n; i++)
    {
        if (p[i].y < p[m].y)
            m = i;
        else if (p[i].y == p[m].y && p[i].x < p[m].x)
            m = i;
    }
    node t = p[m];
    p[m] = p[0];
    p[0] = t;//一定要把最左下的点和最开始的点换位置!!这里处理不好还会出莫名其妙的BUG(不知道为什么,对sort研究不深...)
    sort(p, p + n, cmp);
    getans();
    return 0;
}


/*
9
1 0
3 2
2 0
2 1
2 2
2 3
1 1
0 0
3 3
*/
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值