算法——凸包面积

题目描述

麦兜是个淘气的孩子。一天,他在玩钢笔的时候把墨水洒在了白色的墙上。再过一会,麦兜妈就要回来了,麦兜为了不让妈妈知道这件事情,就想用一个白色的凸多边形把墙上的墨点盖住。你能告诉麦兜最小需要面积多大的凸多边形才能把这些墨点盖住吗? 现在,给出了这些墨点的坐标,请帮助麦兜计算出覆盖这些墨点的最小凸多边形的面积。

输入

多组测试数据。第一行是一个整数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.刚开始看不懂没关系,多看几遍就能理解了。

发布了12 篇原创文章 · 获赞 122 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45703420/article/details/105228167
今日推荐