廣告:
1. 先是放一下本文的::github傳送門:: (不知道爲什麼要放)
2. 今天發現了一個AMA(Ask me anything)的東西, 覺得非常好玩, 就fork了一個放到自己的github裏面,
估計沒有人會來問, 所以就放到這裏拉攏人氣(雖然這裏也拉攏不到) 歡迎大家來玩哦~
地址請戳這個就是傳送門啦~
今天繼續計算幾何(明明已經頹廢了半下午了
計算多邊形面積
我們先從最簡單的多邊形——三角形開始看.
如何計算
S=12ah
這個是最最最常見的公式, 但是這裏我們並不知道高, 要算起來就比較麻煩.S=12bcsinA (其他兩角同理)
這個看上去比較靠譜. 我們算一下AB→×AC→ 的絕對值就好了…S=p(p−a)(p−b)(p−c)−−−−−−−−−−−−−−−−−√,p=a+b+c2
海倫-秦九韶公式啊OvO 這個是可以算的… 但是如果用在多邊形就不是很好用了.
簡單的三角形我們看完了, 我們來看看多邊形..
有些多邊形我們都已經熟知面積公式(比如長方形啊 平行四邊形啊 梯形啊什麼的)
就不再提了.
來看看凸多邊形…
還記得上次可愛的凸多邊形麼_ (:з」∠)_?
我們要計算它的面積的時候, 只需要像圖中一樣劃分成若干個三角形, 然後用公式
計算總面積即可.
但是對於凹多邊形呢? 我們還是先劃一下三角形…
我們會發現如果再按照上面的方法計算的話黃色和紫色(似乎故意標淡了點)的面積會重複計算, 顯然是大於多邊形面積的. 但是數學老師教的面積公式畢竟還是和我們的叉積不一樣的, 公式算的是絕對值, 而叉積是有正負的.
如果
發現剛纔重複的黃色和紫色部分如果用叉乘算一下剛好是一正一負, 多餘的面積都不見了..
再再求一波總和就做完了, 輕鬆加愉快…
而且有了這種正負的定義之後, 我們又有了一種新操作:
以某個點爲出發點向多邊形做向量, 一路做叉積繞個圈求出來的和也等於面積~
爲了方便起見, 完全可以讓”某個點”取原點
且慢! 不是還有一種自我重疊的多邊形嗎? 這個方法也適用嗎?
這個我就不配圖了(其實是嫌麻煩←_←) 完全可以自己畫一下..
發現是完全適用的, 而且自我重疊的部分的面積會計算正確的次數哦~
然後就是最後的總面積有可能是個負值, 可以視情況取個絕對值什麼的^_^
貼代碼(仍然並沒有找到板子題~)(似乎是因爲代碼太簡單了?
//求任意多邊形面積
double polyArea(point *pts,int pcnt,double s=0){
pts[pcnt]=pts[0];
for(int i=0;i<pcnt;++i)
s=pts[i]*pts[i+1]+s;
return 0.5*s;
}
這樣就搞定了OvO
計算多邊形重心
這個也分很多情況啊OvO
而且這個涉及到了高端的數學及物理知識(頭疼ing…
質量集中在頂點上
那就是每個頂點的質量關於座標的平均咯~
質量均勻分佈
還是從簡單開始, 三角形的重心.
懶得再推了, 數學老師說座標應該是
所以我們就同樣可以把多邊形三角剖分, 每個三角形的質量都等效到中心去.
然後就變成了質量集中在頂點上的情況, 質量就取三角形的面積(注意是有向面積)即可.
要注意的比如總面積是0的時候, 因爲要做分母, 所以要特殊處理.
板子題hdu1115適合寫一下.
不過又被-0.00卡翻.. 做了一波優化把
代碼:
#include <cmath>
#include <cstdio>
const double eps=1e-9;
int dcmp(const double &a){
if(fabs(a)<eps) return 0;
return a<0?-1:1;
}
struct point{
double x,y;
point(double X=0,double Y=0):x(X),y(Y){}
}poly[1000010],s;
double operator *(const point &a,const point &b){
return a.x*b.y-a.y*b.x;
}
point polyCenter(point *pts,int pcnt,double sx=0,double sy=0,double area=0){
pts[pcnt]=pts[0]; double ar;
for(int i=0;i<pcnt;++i){
ar=pts[i]*pts[i+1];
sx+=(pts[i].x+pts[i+1].x)*ar; //這裏如果寫sx+=(pts[i].x+pts[i+1].x)/3*ar;
sy+=(pts[i].y+pts[i+1].y)*ar; //這個地方寫sy+=(pts[i].y+pts[i+1].y)/3*ar;
area+=ar;
} area*=3; //而這個地方不寫的話就會被卡精度:-(
return point(sx/area,sy/area);
}
int main(){
int T; scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i=0;i<n;++i)
scanf("%lf%lf",&poly[i].x,&poly[i].y);
s=polyCenter(poly,n);
printf("%.2lf %.2lf\n",s.x,s.y);
}
}
質量不均勻分佈
這個據說要用到積分?
反正我是不會的←_←
等見到再考慮學不學吧..
估計(希望)我是見不到了(flag
然後還有一些點或許因爲太麻煩, 或許因爲不常見還沒有學到..
比如什麼求多邊形之內最大的圓之類的.
據說特別麻煩, 等到有空或者用得到的時候再研究吧.
下次就該學學”更計算幾何”的一些知識了
比如凸包.
再隨便多說幾句:
遇到多邊形的問題要先考慮(讀題)看分不分凹凸, 是不是簡單.
一般讓多邊形第n個點等於第0個點做起來會很舒服.
計算幾何都是毒瘤題見到還是直接棄療吧←_←
但是這篇文章的長度似乎不太夠…
我們再加一丟丟內容吧…
平面最近點對
暴力枚舉每一對顯然就是
似乎有一些玄學的做法比如隨機轉個角度防卡然後分塊, 但是這種做法看着就不科學…
我們要思考科學的方法, 比如考慮分治解決問題.
先將所有點按橫座標排個序.
最近點對的這兩個點的分佈只可能有三種情況:
都在左邊、都在右邊、左右各一.
對於前兩種情況遞歸下去即可.
我們主要來處理左右各一的情況.
我們假設左右兩邊遞歸後求出的值的較小者爲
那很顯然我們只需要考慮[mid-d,mid]和[mid+d,mid]中的點.
如果還是暴力 比較壞的情況複雜度跟暴力並沒有什麼區別, 還是
但是因爲要求的是最近點對, 所以我們可以限制一波.
對於左側的P點來說, 假如說
而這個矩形中最多放多少個互相距離不超過
爲什麼呢? 我們將寬平均分成2份, 高平均分成3份,(紅色) 這樣就形成了一個2*3的格子.
每個格子的寬就是
也就是說不可能存在一個格子中能存在兩個距離大於
那麼根據抽屜原理, 最多就只有6個點了.
所以我們只需要找這些點進行檢索即可, 這樣就保證複雜度不會太高了.
還有一點小細節就是我們按
代碼:
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const double eps=1e-9;
int dcmp(const double &a){
if(fabs(a)<eps) return 0;
return a<0?-1:1;
}
struct point{
double x,y;
point(double X=0,double Y=0){}
}p[200020];
int t[200020];
inline bool cmpx(const point &a,const point &b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
inline bool cmpy(const int &a,const int &b){
return p[a].y<p[b].y;
}
inline double dist(const point &a,const point &b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double solve(int l,int r){
if(r==l) return 1e9;
if(r-l==1) return dist(p[l],p[r]);
int mid=(l+r)>>1;
double dl=solve(l,mid);
double dr=solve(mid+1,r);
if(dr<dl) dl=dr;
int tot=0; double dis=0;
for(int i=l;i<=r;++i)
if(dcmp(fabs(p[i].x-p[mid].x)-dl)<0)
t[tot++]=i; //合法的點才加入數組
sort(t,t+tot,cmpy);
for(int i=0;i<tot;++i)
for(int j=i+1;j<tot&&p[t[j]].y-p[t[i]].y<dl;++j){
if((dis=dist(p[t[i]],p[t[j]]))<dl) dl=dis;
} //左右兩邊都在搜所以只需要考慮下半個矩形
return dl;
}
inline int gn(int a=0,char c=0){
for(;c<'0'||c>'9';c=getchar());
for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
}
int main(){
int n=gn();
for(int i=1;i<=n;++i) p[i].x=gn(),p[i].y=gn();
sort(p+1,p+n+1,cmpx);
printf("%.4lf",solve(1,n));
}
那麼就這樣咯~
這一篇我竟然拖了兩天..