旋转卡壳——模板(对踵点)

这东西学了我大概两天吧。。其实不应该学这么久的,但是这两天有点小困,然后学习时间被削了很多\(QwQ\)

说几个坑点。

- 对于题目不保证有凸包的情况,要选用左下角的点,而非单纯的最下边的点构造凸包。
- 对于凸包中只有\(1/2\)个点的情况,要注意特殊判断。
算法流程就比较简单了。先构造一个凸包,然后利用对踵点都是逆时针跑(类似于两把尺子卡着凸包转)的原理,每次判断到当前直线距离最远的点,更新当前对踵点即可。
例题 【luogu P1452】Beauty contest
#include <bits/stdc++.h>
#define N 50010
using namespace std;

struct point {
    int x, y;
}arr[N], hull[N];

int n, top;

int cross (point u1, point u2, point v1, point v2) {
    return (u2.x - u1.x) * (v2.y - v1.y) - (u2.y - u1.y) * (v2.x - v1.x);
}

int point_dis (point u, point v) {
    return (v.x - u.x) * (v.x - u.x) + (v.y - u.y) * (v.y - u.y);
}

bool cmp (point lhs, point rhs) {
    if (cross (arr[1], lhs, arr[1], rhs) < 0) return false;
    if (cross (arr[1], lhs, arr[1], rhs) > 0) return true;
    return point_dis (arr[1], lhs) < point_dis (arr[1], rhs);
}

void get_hull () {
    sort (arr + 2, arr + 1 + n, cmp);
    hull[++top] = arr[1];
    for (int i = 2; i <= n; ++i) {
        while (top > 1 && cross (hull[top - 1], hull[top], hull[top], arr[i]) <= 0) --top;
        hull[++top] = arr[i];
    }
    hull[top + 1] = arr[1];
}

int get_ans () {
    if (top == 1) return 0;
    if (top == 2) return point_dis (hull[1], hull[2]);
    int v = 2, ans = 0;
    for (int u = 1; u <= top; ++u) {
        while (cross (hull[u], hull[u + 1], hull[u + 1], hull[v]) <=
               cross (hull[u], hull[u + 1], hull[u + 1], hull[v + 1])) {
            v = v == top ? 1 : v + 1;
        }
        ans = max (ans, max (point_dis (hull[u], hull[v]), point_dis (hull[u + 1], hull[v])));
    }
    return ans;
}

int main () {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> arr[i].x >> arr[i].y;
        if (arr[i].y < arr[1].y || (arr[i].y == arr[1].y && arr[i].x < arr[1].x)) {
            swap (arr[i], arr[1]);
        }
    }
    get_hull ();
    cout << get_ans () << endl;
}

转载于:https://www.cnblogs.com/maomao9173/p/10395499.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值