凸包的各种问题以及模板

2 篇文章 0 订阅
1 篇文章 0 订阅

一:求凸包的简洁板子

1:求凸包

#include <iostream>
#include <algorithm>
#include <iomanip>

using namespace std;
const int maxn = 50010;
struct Point {
    int x, y;
    bool operator < (Point const& rhs) const {//重载为类的成员函数的时候,形参时运算符的右操作数
        return (x < rhs.x) || (x == rhs.x && y < rhs.y);
    }
};

int Cross(Point const& O, Point const& A, Point const& B)
{
    int xoa = A.x - O.x;
    int xob = B.x - O.x;
    int yoa = A.y - O.y;
    int yob = B.y - O.y;
    return xoa * yob - xob * yoa;
}
double Dis(Point const& A, Point const& B) 
{
    double xoa = A.x - B.x;
    double xob = A.y - B.y;
    return sqrt(xoa * xoa + xob * xob);
}
int Andrew(Point p[], int n, Point ch[])
{
    sort(p, p + n);
    int m = 0;
    for (int i = 0; i < n; i++) { //下凸包
        while (m > 1 && Cross(ch[m - 2], ch[m - 1], p[i]) < 0) m--;
        ch[m++] = p[i];
    }
    int k = m;
    for (int i = n - 2; i >= 0; i--) {  //上凸包
        while (m > k && Cross(ch[m - 2], ch[m - 1], p[i]) < 0) m--;
        ch[m++] = p[i];
    }
    if (n > 1) m--;
    return m;
}
Point p[maxn], ch[maxn];
int main()
{
    int n;
    while (cin >> n)
    {
        for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;
        int m = Andrew(p, n, ch); //求凸包

        ………………
    }
    return 0;
}

随笔语录
//旋转卡壳的核心思想
1:首先过凸包的任何一个顶点做一条直线,但是我们要保证凸包位于直线的一侧。

2:过凸包的另外一个顶点做该直线的平行线,于是这一对点可以称为凸包的一对踵点(一个n边凸边形最多有3*n/2(向上取整)对蹱点;

3:再编程的时候我们为了方便实现,通常我们是将其中的一条直线旋转到与凸包的一条边重合,我们可以简单的想象成这两条直线卡住了凸包的一条边和一个顶点;

4:现在我们来考虑,如何计算凸包的直径呢?先求凸包上的点到直线的最大距离,凸包上的点到对应边的距离是呈现一个单峰函数的形式,点到直线的距离是呈现一个先上升到最大值后然后下降,点到直线的距离我们可以转换成三角线的面积来求;

5:枚举每一对踵点,更深刻的讲是枚举每一条边,这条边的两个端点分别用i和i+1来表示,对应平行线的的一个点我们用q来表示,用while循环,当三角形i,i+1,q+1的面积比i,i+1,q的面积大的时候,我们就更新q,让q自增1,记得要取余凸包顶点的个数,然后我再比较q这个点和对应直线两个端点之间的距离取大的值,随着一条直线的旋转,不断更新最大值,我们就可以将凸包的直径求出来。




随手笔记
//求凸包的核心思想
1:叉积的定义:当前向量和新的向量叉乘,如果结果大于0

求三角形的最大面积

//旋转卡壳法
        int ans = 0;
        for (int i = 0; i < m; i++) {
            int q = 1;
            for (int j = i + 1; j < m; j++) {
                while (Cross(ch[i], ch[j], ch[q + 1]) > Cross(ch[i], ch[j], ch[q]))
                    q = (q + 1) % m;
                ans = max(ans, Cross(ch[i], ch[j], ch[q]));
            }
        }
        printf("%.2lf\n",ans/2);

求凸包的最大直径

//旋转卡壳法求最大半径
        if (m == 1) {
            printf("%.2ld\n", Dis(ch[0], ch[1]));
        }
        else {
            double ans = 0;
            ch[m] = ch[0];//把第一个点放到最后
            int j = 2;
            for (int i = 0; i < m; i++) {
                while (Cross(ch[i], ch[i + 1], ch[j]) < Cross(ch[i], ch[i + 1], ch[j + 1]))
                    j = (j + 1) % m;
                ans = max(ans,max(Dis(ch[j], ch[i]), Dis(ch[j], ch[i + 1])));
            }
            printf("%.2lf\n", ans);
        }

求凸包的周长

        if (n == 1)
            printf("0.00\n");
        else if (n == 2)
            printf("%.2f\n", Dis(ch[0], ch[1]));
        else{
            double ans = 0;//代表周长
            ch[m] = ch[0];
            for (int i = 1; i <= m; i++)
                ans += Dis(ch[i], ch[i - 1]);
            printf("%.2f\n", ans);
        }

二:判断直线和直线的位置关系

#include<iostream>
#include<algorithm>
using namespace std;
struct Point
{
    int x, y;
};
struct Line
{
    int a, b, c;
};
int line(int x1, int y1, int x2, int y2)   //向量(x1,y1),(x2,y2);
{
    return x1 * y2 - y1 * x2;
}
Line lineform(int x1, int y1, int x2, int y2)   //ax + by + c = 0;
//构造直线,返回这条直线的类型
{
    Line temp;
    temp.a = y2 - y1;
    temp.b = x1 - x2;
    temp.c = x2 * y1 - x1 * y2;
    return temp;
}
double x, y;
void lineintersect(Line l1, Line l2) //求两条直线的交点
{
    double d = l1.a * l2.b - l2.a * l1.b;
    x = (l2.c * l1.b - l1.c * l2.b) / d;
    y = (l2.a * l1.c - l1.a * l2.c) / d;
}
bool gongxian(Point p1, Point p2, Point p3,Point p4) {//判断是否共线
    if (line(p2.x - p1.x, p2.y - p1.y, p3.x - p1.x, p3.y - p1.y) == 0 && line(p2.x - p1.x, p2.y - p1.y, p4.x - p1.x, p4.y - p1.y) == 0)
        return true;
    return false;
}
bool pinxing(Point p1, Point p2, Point p3, Point p4) {//判断是否平行
    if (line(p1.x - p2.x, p1.y - p2.y, p3.x - p4.x, p3.y - p4.y) == 0)
        return true;
    return false;
}

随笔语录
//判断直线类型的步骤
1:首先判断两直线是否共线

2:再判断两直线是否平行

3:如果前面两个条件都不满足的话,就一定有交点,先求出两条直线的一半式方程,然后求两直线的交点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米兰的小码匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值