題目描述
麥兜是個淘氣的孩子。一天,他在玩鋼筆的時候把墨水灑在了白色的牆上。再過一會,麥兜媽就要回來了,麥兜爲了不讓媽媽知道這件事情,就想用一個白色的凸多邊形把牆上的墨點蓋住。你能告訴麥兜最小需要面積多大的凸多邊形才能把這些墨點蓋住嗎? 現在,給出了這些墨點的座標,請幫助麥兜計算出覆蓋這些墨點的最小凸多邊形的面積。
輸入
多組測試數據。第一行是一個整數T,表明一共有T組測試數據。
每組測試數據的第一行是一個正整數N(0< N < = 105),表明了墨點的數量。接下來的N行每行包含了兩個整數Xi和Yi(0<=Xi,Yi<=2000),表示每個墨點的座標。每行的座標間可能包含多個空格。
輸出
每行輸出一組測試數據的結果,只需輸出最小凸多邊形的面積。面積是個實數,小數點後面保留一位即可,不需要多餘的空格。
樣例輸入
2
4
0 0
1 0
0 1
1 1
2
0 0
0 1
樣例輸出
1.0
0.0
代碼
#include<iostream>
#include<cmath>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct{
int x,y;
}Coor;
Coor a[5000];
double area;
double Area(int p1, int p2, int p3){
return 0.5*fabs((a[p2].x -a[p1].x )*(a[p3].y - a[p2].y ) - (a[p3].x - a[p2].x )*(a[p2].y - a[p1].y ));
}
//判斷位置,小於零,逆,反之則順
bool pos( int p1,int p2, int p3){
int m = ((a[p2].x -a[p1].x )*(a[p3].y - a[p2].y));
if(m > 0) return true;
return false;
}
void convex_hull(bool pos1, int p1, int p2){
int p = -1;
double area_max = -1.0;
for(int i = p1+1; i < p2 ;i++){
if( pos1 == pos(p1, p2, i) ) continue;
if(Area(p1, p2, i) > area_max ){
area_max = Area(p1, p2, i);
p = i;
}
}
if( p == -1) return ;
area += area_max;
convex_hull( pos1, p1, p);
convex_hull( pos1, p, p2);
}
bool cmp(Coor p1, Coor p2){
return p1.x < p2.x ;
}
int main(){
int n,m;
cin>>n;
while(n>0){
cin>>m;
area = 0;
for(int i = 0; i < m; i++){
cin>>a[i].x >>a[i].y ;
}
sort(a,a+m,cmp);//從小到大排序
convex_hull(true,0,m-1);
convex_hull(false,0,m-1);//上包和下包的面積分開算
printf("%.1f\n",area);
n--;
}
return 0;
}
思路
1.使用了分治法,將多個點的圍成的最大面積分成多個三角形的面積之和;
2.所以要明白已知三點求面積的公式:S=1/2 [( x1 y2 - x2 y1) + (x2 y3 - x3 y2)+(x3 y1 - x1 y3)](代碼裏面的公式也是正確的),其中A(x1,y1),B(x2,y2),C(x3,y3);
3.要注意的是第二點的 S 可能是負數,那麼 S 的正負性可判斷C點(第三點在構成直線的另兩點的位置),所以求面積要帶上絕對值。
4.剛開始看不懂沒關係,多看幾遍就能理解了。