1. 程式人生 > >hdoj-2036題解-向量積法求任意多邊形面積

hdoj-2036題解-向量積法求任意多邊形面積

該題題意就是逆時針給出點的座標,求這個多邊形的面積。下面就寫一下如何用向量積法求多邊形面積。

向量積法與面積


上圖說明了如何利用向量求得三角形的面積,下面介紹一下所謂的右手法則:
如圖,2個三角形ABC,唯一的區別在於上面的三角形ABC的標識是逆時針,而下面的三角形標識是順時針。如果利用向量叉積,由於乘的是向量的絕對值,所以AB與AC在上或者在下是沒有區別的。但是如果不使用絕對值,而是寫成行列式的形式,就要考慮方向的問題了。所以簡單(不負責任)地說,所謂右手法則就是:當逆時針(右手大拇指朝向)方向排列點的時候組成的向量求的的結果是正數,反之是負數。(上面並不是標準解答,關於定義可參考wikipedia)那麼以上2個三角形轉化為行列式的時候就是下圖:

根據行列式的性質,我們也能知道兩者的值是相反的。 既然如此,我們在得到逆時針序的3點座標的情況下,利用行列式即可得到面積。例:
核心程式碼為:
int S = (0.5)*(x1*y2+x2*y3+x3*y1-x3*y2-x2*y1-x1*y3);

N邊形劃分為三角形


如上圖,任何一個N邊形都能劃分為N-3個三角形,那麼根據上面的公式,我們逆時針獲取點,就像下圖一樣,令單個三角形的面積和累加即可得到N邊形的面積。
因為右手定則,一定要逆時針。而該題輸入要求就正好是逆時針輸入。並且可以看出:A點恆不變,另兩個點是移動狀態,那麼我們就可以寫出程式碼:
int beginx, beginy, lastx, lasty, x, y;
double ans;
cin >> beginx >> beginy >> lastx >> lasty >> x >> y;
ans = (double)(0.5)*(beginx*lasty + lastx*y + x*beginy - x*lasty - lastx*beginy - beginx*y);
以上程式碼可以得到第一個三角形ABC的面積,下面進入迴圈:
n -= 3;
while (n--) {
	cin >> x >> y;
	ans += (double)(0.5)*(beginx*lasty + lastx*y + x*beginy - x*lasty - lastx*beginy - beginx*y);
	lastx = x;
	lasty = y;
}

最終即可得到解ans。

凹邊形面積

我們上面的例子都是凸邊形,對於凹邊形而言我們仍然可以得到正解,就是因為有右手定則。
如上圖的凹邊形,我們仍然按照逆時針順序來求解,第一個三角形ABC,得到實際上是包括虛線在內的整體面積,那麼第二個三角形ACD,可以看到是順時針了,絕對值是有虛線的ACD面積,那麼因為是順時針,用行列式求出的值是負數。兩個行列式值相加,正好是大三角形(包括虛線)ABC面積減去小三角形ACD的面積。得到的仍然是凹邊形的面積。

C++程式碼

已AC
#include<iostream>


using namespace std;


int main() {
    int n;
    while (cin >> n) {
        if (n == 0) break;
        int beginx, beginy, lastx, lasty, x, y;
        double ans;
        cin >> beginx >> beginy >> lastx >> lasty >> x >> y;
        ans = (double)(0.5)*(beginx*lasty + lastx*y + x*beginy - x*lasty - lastx*beginy - beginx*y);
        lastx = x;
        lasty = y;
        n -= 3;
        while (n--) {
            cin >> x >> y;
            ans += (double)(0.5)*(beginx*lasty + lastx*y + x*beginy - x*lasty - lastx*beginy - beginx*y);
            lastx = x;
            lasty = y;
        }
        printf("%.1lf\n", ans);
    }


    system("pause");
    return 0;
}