AC大吉
AC神符保佑你
题目描述
思路:
见另一篇文章分治法求凸包
先分为上下两个包,然后使用分治法递归求解面积
求面积的方法,先找顶点,把面积保留,然后对顶点与底边划分出来的两个三角形递归求面积
代码如下
#include<iostream>
#include<stdio.h>
using std::cin;
struct Node
{
int x;
int y;
};
Node p[105];
int calSquareS(int i, int j, int k) {
int s= p[i].x * p[j].y + p[j].x * p[k].y + p[k].x * p[i].y - p[i].y * p[j].x - p[j].y * p[k].x - p[k].y * p[i].x;
if(s>0) return s;
if(s<0) return (-1)*s;
}
//1在上方,0在下方,-1在直线上
int isAbove(int i, int j, int amb) {
int answer = (p[j].y - p[i].y) * (p[amb].x - p[i].x) - (p[amb].y - p[i].y) * (p[j].x - p[i].x);
if (answer == 0) return -1;
if(answer < 0) return 1;
if(answer >0 )return 0;
}
int doMerge(int* g,int n,int min,int max) {
if (n == 0) return 0;
int s = calSquareS(min, max, *(g));
if (n == 1) return s;
//找最高
int maxS = s,maxP=*g;
for (int i = 1; i < n; i++) {
s = calSquareS(min, max, *(g + i));
if (maxS < s) {
maxS = s;
maxP = *(g+i);
}
}
//划分包递归计算
int left[105],right[105],numL=0,numR=0;
for (int i = 1; i < n; i++) {
if (*(g + i) == maxP) continue;
//丢掉正下方
if (p[*(g + i)].x < p[maxP].x) {
left[numL] = *(g + i);
numL++;
}
if (p[*(g + i)].x > p[maxP].x) {
right[numR] = *(g + i);
numR++;
}
}
return doMerge(left, numL, min, maxP) +doMerge(right, numR, maxP, max) + maxS;
}
void calS() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i].x >> p[i].y;
}
// 上下包
int min = 0, max = 0;
for (int i = 0; i < n; i++) {
if (p[i].x < p[min].x) min = i;
if (p[i].x > p[max].x) max = i;
}
//分上下包
int under[105], undi = 0;
int above[105], aboi = 0;
for (int i = 0; i < n; i++) {
if (i == min || i == max) {
continue;
}
int isA = isAbove(min, max, i);
if (isA==1) {
above[aboi] = i;
aboi++;
}
else if(isA==0)
{
under[undi] = i;
undi++;
}
}
//计算
int aboveS = doMerge(above, aboi,min,max);
int unserS = doMerge(under, undi,min,max);
printf("%.1f\n", (aboveS + unserS) / 2.0);
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
calS();
}
return 0;
}