算法——凸包面積

題目描述

麥兜是個淘氣的孩子。一天,他在玩鋼筆的時候把墨水灑在了白色的牆上。再過一會,麥兜媽就要回來了,麥兜爲了不讓媽媽知道這件事情,就想用一個白色的凸多邊形把牆上的墨點蓋住。你能告訴麥兜最小需要面積多大的凸多邊形才能把這些墨點蓋住嗎? 現在,給出了這些墨點的座標,請幫助麥兜計算出覆蓋這些墨點的最小凸多邊形的面積。

輸入

多組測試數據。第一行是一個整數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.剛開始看不懂沒關係,多看幾遍就能理解了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章