計算幾何--Graham 凸包掃描法模板(高封裝)

2020.6.30
下午不想動腦子了,乾脆來學習一下計算幾何。果然寫數據結構就是爽,不用怎麼動腦子就行。這個graham掃描法oi考得其實並不算很多,倒是acm一天到晚考這個東西。去年去p大大概聽郭神講過這個,就是排序完不斷尋找叉積大於0(向外拐)的上凸殼,然後同樣方法掃一遍下凸包就行,聽說會被卡成n方,不過我覺得icpc的命題組還是可以信賴的,學了再說。新隊友tg2=,沒辦法計算幾何只能我來抗了。這個算法不是很難,我對一些能優化的地方優化了一下,就是可能這樣一來常數有點大了。但是絕對好懂,瞭解過這個算法大概的步驟的一看我的代碼應該就懂了,我是把能封裝的東西全部封裝了一遍,爲了可讀性,用了工廠模式和typedef把vector和point公用一個結構體,雖然本身也就是一樣,但是這樣一來可讀性屬實增加了不少,看代碼吧。就是進棧出棧。

代碼:

#include <bits/stdc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步兩步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = x * 10 + s - '0';s = getchar();}
    return x * sign;
}//快讀
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
struct point{
    double x,y;
    point(double _x = 0.00,double _y = 0.00):x(_x), y(_y){}
    double operator^(const point &rhs)const {
        return x * rhs.y - y * rhs.x;//叉積順時針大於0,平行等於0,逆時針小於0
    }//叉積
    static point make_vector(point p1, point p2){
        return point(p2.x - p1.x,p2.y - p1.y );
    }
    bool operator<(const point &p2)const{
        return y == p2.y ? x < p2.x : y < p2.y;
    }
}a[limit];
double sq(double i){
    return i * i;
}
double dist(point x , point y){
    return sqrt(sq(x.x - y.x) + sq(x.y - y.y));//求歐幾里得距離
}
int n;
point stk[limit];
int top;
typedef point vect;
int main() {
#ifdef LOCAL
    FOPEN;
#endif
    n = read();
    top = 0;
    rep(i ,1, n){
        double x, y;
        scanf("%lf%lf" , &x, &y);
        a[i].x = x, a[i].y = y;
    }
    sort(a + 1, a + 1 + n);
    stk[++top] = a[1] , stk[++top] = a[2];
    rep(i ,3, n){
        vect u = point::make_vector(stk[top - 1] , stk[top]);
        vect v = point::make_vector(stk[top], a[i]);
        while (top > 1 && (u ^ v) < 0){
            --top;
            u = point::make_vector(stk[top - 1] , stk[top]);
            v = point::make_vector(stk[top], a[i]);
        }
        stk[++top] = a[i];
    }//上凸包
    int threshold = top;
    stk[++top] = a[n] , stk[++top] = a[n - 1];
    per(i ,1,n - 2){
        vect u = point::make_vector(stk[top - 1] , stk[top]);
        vect v = point::make_vector(stk[top], a[i]);
        while (top > threshold + 1 && (u ^ v) < 0){
            --top;
            u = point::make_vector(stk[top - 1] , stk[top]);
            v = point::make_vector(stk[top], a[i]);
        }
        stk[++top] = a[i];
    }
    double ans = 0.0;
    rep(i ,1, top - 1){
        ans += dist(stk[i], stk[i + 1]);
    }
    printf("%.2lf" , ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章