NYOJ3——多邊形重心問題
題目分析:好吧,這個題目基本上話了我一個小時去回顧以前學過的幾何知識。下面我們來一點一點的分析。
1)重心就是重量的中心。其定義就是對整個圖形分別從x方向和y方向進行密度積分,然後除以總面積,就得到了重心的x座標和y座標。這裡由於圖形每一點都是一樣的,也就說說密度平均。好吧,說到積分,很多人就頭疼了,好吧,我也煩這個。OK,換一個說法。多邊形一定可以分成若干個不相交的三角形吧。其實通過重心和多邊形的每一個點相連,就得到了我們要的三角形了。
2)把每一個三角形看成一個質心,那麼我們剛剛所說的對密度進行積分其實分兩個,x方向和y方向。那麼x方向的積分就變成了對所有的三角形把 三角形的面積*該三角形重心的x座標
3)每個三角形的面積怎麼求?
其實在高中的時候我們就知道,已知三角形的兩個邊a,b。s=a*b*sin(ab所夾的角)。當然大學肯定學過叉乘。a×b=|a|*|b|*sin(ab所夾的角)。這裡需要注意叉乘是有方向的,所以這個角必須是從a到b並且符合右手定律的那個角。
4)三角形的重心怎麼求?
這個很簡單啦!三個點的座標的平均就可以了。公式不用我說了吧。
5)關鍵地方來了~
我開始說的把多邊形分成若干個三角形的方法是讓重心與每個點相連,但是這裡重心是我們要求的東西,所以這樣肯定不行。不過聰明的你肯定想到了以多邊形的第一個點為準,然後分別與其它各點相連,然後形成的向量就是(point[0].x-point[i].x,point[0].y-point[i].y)和(point[0].x-point[i+1].x,point[0].y-point[i+1].y)。。或者說相鄰的三個點就可以組成一個三角形則形成的向量就是(point[i].x-point[i-1].x, point[i].y-point[i-1].y)和(point[i].x-point[i+1].x, point[i].y-point[i+1].y)。OK,現在我告訴你,這兩個方法都弱爆了。由於叉乘的特殊性質,前面我說的,它是有方向的,所以我們可以把這個相對的點移到任何一個角落。那麼這個點既然是任意的,為什麼不放在原點呢?你會奇怪為什麼會這樣。因為a×b=-b×a。so,你畫畫圖試試~~~
OK~說了那麼多累死我了,要還是不懂,對照著程式碼看吧~~
#include<stdio.h> #include<math.h> const int N = 10005; typedef struct { double x; double y; }POINT; POINT point[N]; inline double CrossProduct(int i) { return point[i].x * point[i + 1].y - point[i + 1].x * point[i].y; } int main() { int n,t; int i; double temp; double area,x,y; scanf("%d", &t); while(t--) { scanf("%d",&n); for(i = 0; i < n; ++i) scanf("%lf %lf",&point[i].x, &point[i].y); point[n].x = point[0].x;//記下第一個點,形成迴圈 point[n].y = point[0].y; area = 0.0; x = 0.0; y = 0.0; for(i = 0; i < n; ++i) { temp = CrossProduct(i) / 2.0; area += temp; x += temp * (point[i].x + point[i + 1].x) / 3.0; y += temp * (point[i].y + point[i + 1].y) / 3.0; } area = fabs(area);//我說了,叉乘有方向,最後記得取絕對值 if(area < 0.0000001) printf("0.000 0.000\n"); else printf("%.3lf %.3lf\n", area, fabs(x + y) / area); } }