题目描述
麦兜是个淘气的孩子。一天,他在玩钢笔的时候把墨水洒在了白色的墙上。再过一会,麦兜妈就要回来了,麦兜为了不让妈妈知道这件事情,就想用一个白色的凸多边形把墙上的墨点盖住。你能告诉麦兜最小需要面积多大的凸多边形才能把这些墨点盖住吗? 现在,给出了这些墨点的坐标,请帮助麦兜计算出覆盖这些墨点的最小凸多边形的面积。
输入
多组测试数据。第一行是一个整数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.刚开始看不懂没关系,多看几遍就能理解了。