1. 程式人生 > >蠻力法解決凸包問題

蠻力法解決凸包問題

首先,什麼是凸包? 


假設平面上有p0~p12共13個點,過某些點作一個多邊形,使這個多邊形能把所有點都“包”起來。當這個多邊形是凸多邊形的時候,我們就叫它“凸包”。如下圖

 

然後,什麼是凸包問題? 


我們把這些點放在二維座標系裡面,那麼每個點都能用 (x,y) 來表示。 
現給出點的數目13,和各個點的座標。求構成凸包的點?

 

時間複雜度:O(n³)。 
思路:兩點確定一條直線,如果剩餘的其它點都在這條直線的同一側,則這兩個點是凸包上的點,否則就不是。 
步驟:

          1.將點集裡面的所有點兩兩配對,組成 n(n-1)/2 條直線。
           2.對於每條直線,再檢查剩餘的 (n-2) 個點是否在直線的同一側。
如何判斷一個點 p3 是在直線 p1p2 的左邊還是右邊呢?(座標:p1(x1,y1),p2(x2,y2),p3(x3,y3))
 

當上式結果為正時,p3在直線 p1p2 的左側;當結果為負時,p3在直線 p1p2 的右邊。

 

C++程式碼實現

#include <bits/stdc++.h>

using namespace std;

const int maxn = 10005;

typedef struct Point
{
    int x;
    int y;
} point;

point p[maxn];
set<pair<int, int> > s;
int n;

int judge(point p1, point p2, point p3)
{
    int flag = p1.x * p2.y + p3.x * p1.y + p2.x * p3.y - p3.x * p2.y - p2.x * p1.y - p1.x * p3.y;
    if (flag > 0) return 1;
    else if (flag == 0) return 2;
    else return 0;
}

int main()
{
    while (cin >> n && n)
    {
        for (int i = 0; i < n; i++) cin >> p[i].x >> p[i].y;

        s.clear();

        for (int i = 0; i < n; i++)
        {
            int t = 0;

            for (int j = 0; j < n; j++)
            {
                int flag = -1;
                if (i == j) continue;

                for (int k = 0; k < n; k++)
                {
                    if (k == i || k == j) continue;

                    if (flag == -1) flag = judge(p[i], p[j], p[k]);
                    else
                    {
                        int temp = judge(p[i], p[j], p[k]);
                        if (flag == temp || temp == 2) t = 1;
                        else
                        {
                            t = 0;
                            break;
                        }
                    }
                }

                if (t) s.insert(make_pair(p[j].x, p[j].y));
            }

            if (t) s.insert(make_pair(p[i].x, p[i].y));
        }

        set<pair<int, int> >::iterator it = s.begin();

        while (it != s.end())
        {
            printf("(%d, %d)\n", it->first, it->second);
            it++;
        }

    }

    return 0;
}

 

這裡給出2組測試資料

本資料用於臨時性檢測,明天實驗課上會生成更多資料

/*
input1
6
1 3
2 1
4 1
4 3
3 4
6 2

output1
(1, 3)
(2, 1)
(3, 4)
(4, 1)
(6, 2)

input2
14
30 30
50 60
60 20
70 45
86 39
112 60
200 113
250 50
300 200
130 240
76 150
47 76
36 40
33 35

ouput2
(30, 30)
(47, 76)
(60, 20)
(76, 150)
(130, 240)
(250, 50)
(300, 200)
*/