二维凸包 Graham's Scan
凸包是啥??
凸包就是:
給定二維平面上的點集,凸包就是將最外層的點連接起來構成的凸多邊型,它能包含點集中所有的點。
外層的紅線 就是凸包
一般題目會讓你求利用最外層凸包的一些性質如下面這道題
來看一道模板題:HDU - 1348
本題題目就是要求盡可能少的圍墻周長 圍墻內的城堡是多邊形的 而圍墻還要和城堡相隔l距離
可證 實質周長其實就是 城堡的凸包周長 + 以l為半徑的周長之和?
由于多邊形城堡 盡可能少的包圍他其實就是凸包周長 而在凸包的拐角處 要相隔l距離 所以變成了一個圓弧
把圓弧加起來就是圓的周長?
n邊形的內角和公式 :(n-2)*180
n變形外角永遠是360度
所以 可以列式 n×360 - (n-2)×180 -90×n×2 = 360° (n個角 減去內角 在減去多余的90° 畫個圖就能得到)
所以多出來的那些空間可知就是一個360°的整圓
關于這個方法就是先取左下點為基準點?
?然后 對其他點 按照從基準點的x軸逆時針方向射出的極角 掃過的順序排序?
然后再對其中的每前后三個點進行叉乘操作
?
?如果我們以逆時針方向遍歷所有點
n,m,l三個點
n為起點 向m和l點做兩個向量分別是向量a,向量b
向量a*b<0 說明 a在 b的逆時針方向 即是說 m點在l點里面,左邊 若選凸包 我們舍棄a的終點m 而選取b的終點?
若叉乘結果>0說明a在b的順時針方向 也就是 m在l的外邊 右邊
最終將保存下來的點 按順序遍歷求兩點之間的線段長度就可以了
code
#include<bits/stdc++.h>using namespace std; typedef long long ll; const int maxn = 1010; const double pi = acos(-1.0);// 得到PI struct node {double x,y; }p[1010],P[1010];//P內存儲凸包內的店 int t,tot,N; double L; double X(node a,node b,node c) {return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y); }// 計算叉積 double len(node a,node b) {return sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y)); }//兩點之間距離公式 bool cmp(node b,node c) {double pp = X(p[1],b,c);if(pp<0)return 0;else if(pp>0)return 1;else if(pp==0&&len(p[1],b)<len(p[1],c))return 1;else return 0; }//掃描排序 int main() {scanf("%d",&t);for(int cas = 1;cas<=t;cas++){if(cas!=1)puts("");scanf("%d%lf",&N,&L);for(int i=1;i<=N;i++)scanf("%lf%lf",&p[i].x,&p[i].y);double ans = pi*2.0*L;for(int i=2;i<=N;i++){if(p[1].y>p[i].y)swap(p[1],p[i]);else if(p[1].y==p[i].y&&p[1].x>p[i].x)swap(p[1],p[i]);}//找基準點sort(p+2,p+1+N,cmp);P[1]=p[1];P[2]=p[2];tot=2;for(int i=3;i<=N;i++){while(tot>1&&X(P[tot-1],P[tot],p[i])<=0)tot--;tot++;P[tot] = p[i];}//篩選點for(int i=1;i<tot;i++){ans+=len(P[i],P[i+1]);}//圍圈求和ans+=len(P[1],P[tot]);printf("%.0lf\n",ans);}return 0; }
總結
以上是生活随笔為你收集整理的二维凸包 Graham's Scan的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 解决yum命令失效,vim: comma
- 下一篇: jqgrid学习(三)