凸包 和 旋轉卡殼(模板)
阿新 • • 發佈:2021-11-06
凸包 首先 極角排序, 選一個初始的點。然後,自己去看吧,說不清楚。
洛谷上過了兩個模板題,看題解 和OI wiki
P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二維凸包
#include <bits/stdc++.h> using namespace std; const int N = 1e4+10; int n,cnt; struct Point{ double x,y; }p[N],s[N]; double dist(Point a,Point b) { return sqrt( (a.x -b.x)*(a.x - b.x) + (a.y -b.y) * (a.y -b.y)); } double cross(double x1, double y1, double x2, double y2) { return (x1 * y2 - x2 * y1); } double check(Point a,Point b,Point c,Point d) { return cross(b.x - a.x, b.y - a.y, d.x - c.x ,d.y - c.y); } bool cmp(Point p1,Point p2) { double tmp=check(p[1],p1,p[1],p2); if(tmp>0) return 1; if(tmp==0&&dist(p[0],p1)<dist(p[0],p2)) return 1; return 0; } int main() { cin>>n; for(int i = 1; i <= n; i ++) { scanf("%lf%lf",&p[i].x, &p[i].y); if(i!=1&&(p[i].x <p[1].x ||p[i].x == p[1].x && p[i].y <p[1].y))//這是是去重 { swap(p[i],p[1]); } } sort(p + 2,p + n + 1,cmp); // for(int i = 1;i <= n ;i ++) cout<<p[i].x<<","<<p[i].y<<endl; s[1] = p[1]; cnt = 1; for(int i = 2; i <= n; i ++) { while(cnt > 1 && check(s[cnt - 1], s[cnt], s[cnt], p[i]) <= 0) cnt --; cnt ++; s[cnt] = p[i]; } s[cnt + 1] = p[1]; double ans = 0; //cout<<p[1].x<<" "<<p[1].y<<endl; for(int i = 1; i <= cnt; i ++) { // cout<<dist(s[i], s[i + 1])<<endl; ans += dist(s[i], s[i + 1]); } printf("%.2lf",ans); return(0); }
P1452 [USACO03FALL]Beauty Contest G /【模板】旋轉卡殼
#include <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int N = 1e5+10; int n,cnt; struct Point{ int x,y; }p[N],s[N]; LL dist(Point a,Point b){ return (a.x -b.x)*(a.x - b.x) + (a.y -b.y) * (a.y -b.y); } LL cross(int x1, int y1, int x2, int y2){ return (x1 * y2 - x2 * y1); } LL check(Point a,Point b,Point c,Point d){ //可以算用來複用算面積 return cross(b.x - a.x, b.y - a.y, d.x - c.x ,d.y - c.y); } bool cmp(Point p1,Point p2){ LL tmp=check(p[1],p1,p[1],p2); if(tmp>0) return 1; if(tmp==0&&dist(p[0],p1)<dist(p[0],p2)) return 1; return 0; } LL getMax() //求凸包的直徑 { if(cnt == 2) return dist(s[1],s[2]); else { int j = 3; LL ans = 0; for(int i = 1;i <= cnt; i ++) { while(check(s[i],s[i+1],s[i],s[j]) < check(s[i],s[i+1],s[i],s[j+1])) j = j % cnt + 1; //這個地方注意了 之前寫的雖然過了但是誤打誤撞出來的 ans=max(ans,max ( dist(s[i],s[j]), dist(s[i+1],s[j])) ); } return ans; } } int main() { cin>>n; for(int i = 1; i <= n; i ++) { scanf("%d%d",&p[i].x, &p[i].y); if(i > 1 && (p[i].x < p[1].x || p[i].x == p[1].x && p[i].y < p[1].y)) //這裡是為了三個點一條線時應選取最長的線段,故意造資料卡 swap(p[1],p[i]); } sort(p + 2,p + n + 1,cmp); cnt=1; s[1] = p[1]; for(int i = 2; i <= n; i ++) { while(cnt > 1 && check(s[cnt - 1], s[cnt], s[cnt], p[i]) <= 0) cnt --; cnt ++; s[cnt] = p[i]; } // cout<<cnt<<endl; // for(int i=1;i<=cnt;i++) cout<<s[i].x<<" "<<s[i].y<<endl; s[cnt + 1] = p[1]; //凸包部分完成 LL ans = getMax(); printf("%lld",ans); return(0); }