《凸包》

本来都是不搞计算几何的..

但是由于斜率dp里要用到,所以被迫学一下。

定义:覆盖所有平面内的点的最小的凸多边形。

Graham算法:

以某个点为起点左右转移来维护凸包的边界的思路。

利用极角排序来对过程优化。且维护一个栈。

洛谷P2742

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 5e5 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e16
#define dbg(ax) cout << "now this num is " << ax << endl;

int n;
struct Point{
    double x,y;
    double Distance(Point p1,Point p2) {//两点间距离
        return sqrt((p2.y-p1.y) * (p2.y-p1.y) + (p2.x-p1.x) * (p2.x-p1.x));
    }
    double check(Point a1,Point a2,Point b1,Point b2) {//检查叉积是否大于0,如果是a就逆时针转到b 
        return (a2.x-a1.x) * (b2.y-b1.y) - (b2.x-b1.x) * (a2.y-a1.y);
    }
}p[N],s[N];
bool cmp(Point p1,Point p2) {
    double tmp = p[0].check(p[1],p1,p[1],p2);
    if(tmp > 0) return true;
    if(tmp == 0 && p[0].Distance(p[0],p1) < p[0].Distance(p[0],p2)) return true;
    return false;
}
double Graham() {
    sort(p + 2,p + n + 1,cmp);
    s[1] = p[1];//最低点
    int cnt = 1;
    for(int i = 2;i <= n;++i) {
        while(cnt > 1 && p[0].check(s[cnt - 1],s[cnt],s[cnt],p[i]) < 0) cnt--;//踢走栈顶
        s[++cnt] = p[i];
    }
    s[cnt + 1] = p[1];
    double ans = 0;
    for(int i = 1;i <= cnt;++i) ans += p[0].Distance(s[i],s[i + 1]);//计算凸包周长
    return ans;
}
int main() {
    scanf("%d",&n);
    for(int i = 1;i <= n;++i) {
        scanf("%lf %lf",&p[i].x,&p[i].y);
        if(i != 1 && p[i].y < p[1].y) swap(p[i],p[1]);//去重
    }
    double ans = Graham();
    printf("%.2f\n",ans);

    system("pause");
    return 0;
}
View Code

 

posted @ 2021-08-20 11:15  levill  阅读(42)  评论(0编辑  收藏  举报