Empty Convex Polygons
Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 651 Accepted Submission(s): 175
Problem Description
Given a set of distinct points S on a plane, we define a convex hole to be a convex polygon having any of thegiven points as vertices and not containing any of the given points in its interior. In addition to the vertices, other given points may lie on the perimeter of the polygon. We want to find a convex hole as above forming the convexpolygon with the largest area.
Input
This problem has several test cases.
The first line of input contains an integer t (1 ≤ t ≤ 100) indicating the total number of cases. For each test case,the first line contains the integer n (3 ≤ n ≤ 50). Each of the following n lines describes a point with two integers x and y where -1000 ≤ x, y ≤ 1000.
We guarantee that there exists at least one non-degenerated convex polygon.
Output
For each test case, output the largest area of empty convex polygon, with the precision of 1 digit.
Remark: The corollary of Pick’s theorem about the polygon with integer coordinates in that says the area of it iseither ends to .0 or .5.
Sample Inpu
4
3
0 0
1 0
0 1
5
0 0
1 0
2 0
0 1
1 1
5
0 0
3 0
4 1
3 5
-1 3
6
3 1
1 0
2 0
3 0
4 0
5 0
Sample Output
0.5
1.5
17.0
2.0
题意:给出 n 个点,要求从这 n 个点中选择出若干个点,构成一个空凸包(即土包内不包含其他点),且要求最大符合要求的凸包的面积
做空凸包:每次枚举两个点与原点构成三角形后,判断之前的点是否有在这个三角形内的,如果有,这个三角形不能构成空凸包,跳过,如果没有,那么可以计算面积
dp[i][j] 表示 以 点i 和 点j 连成的直线作为倒数第二条线的凸包的最大面积
那么 dp[i][j] = max(dp[i][j],dp[j][k] + 空三角形面积) k 为 j 之前的点
为了找到最大面积的凸包,要枚举整个凸包左下角的那个点作为起点,然后做凸包,取最大面积
/**
Author: LinZhiQ
Date: 2018-10-01 13:31
Graham扫描法 + DP 求空凸包
*/
#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const double PI = acos(-1.0);
struct Point {
double x,y;
Point() {}
Point(double _x, double _y) {
x = _x;
y = _y;
}
Point operator -(const Point &b)const {
return Point(x - b.x, y - b.y);
}// (点 a - 点 b) 表示以 b 为坐标轴原点重新定义 a 的坐标
double operator ^(const Point &b)const {
return x * b.y - y * b.x;
}//Cross 比较 点 a 与 点 b 到原点 连线的斜率 ,a的斜率小则返回值 大于零,等于零表示在同一直线
double operator *(const Point &b)const {
return x * b.x + y * b.y;
}//Dot 点自己 乘 自己 表示 点到原点距离的平方 也就是点乘
void transXY(double B) {
double tx = x,ty = y;
x = tx * cos(B) - ty * sin(B);
y = tx * sin(B) + ty * cos(B);
}
} p[105], t[105];
bool cmp1(const Point &a, const Point &b) {
return (a.y != b.y ? a.y < b.y : a.x < b.x);
} // 按照点的 y 坐标从小到大,x 坐标从小到大 (逆时针)
bool cmp2(const Point &a, const Point &b) {
return ((a ^ b) == 0 ? (a * a) < (b * b) : (a ^ b) > 0);
} // 极角排序,如果 a与b 在同一直线,那就与原点距离近的优先,否则极角小的优先
int T, n, m;
double dp[105][105], ans;
void init() {
for(int i = 0; i <= m; i++) {
for(int j = 0; j <= i; j++) {
dp[i][j] = 0;
}
}
}
void solve() {
init();
for(int i = 2; i <= m; i++) {
for(int j = 1; j < i; j++) {
if((t[i] ^ t[j]) == 0) // 如果与前点斜率相同(同一直线,则跳过)
continue;
bool flag = true;
// 此时选定了两个点 t[i] 和 t[j]
for(int k = j + 1; k < i; k++) { // 遍历第三个点
if((t[k] ^ t[i]) > 0 && (t[j] ^ t[k]) > 0 && ((t[i] - t[j]) ^ (t[k] - t[j])) > 0) {
// 如果第三个点被 原点 i 和 j 包围,那么说明这个凸包不是空凸包
flag = false;
break;
}
}
if(!flag) {
continue;
}
// 如果这个三个点围成的三角形是个空凸包
dp[i][j] = t[j] ^ t[i]; // 多边形面积计算公式 p[a] ^ p[b] / 2
if((t[j] ^ t[j - 1]) != 0) { // 如果上一个点在它右边,那么面积可以拓展
for(int k = 1; k < j; k++) {
if(((t[k] - t[i]) ^ (t[j] - t[i])) > 0) {
dp[i][j] = max(dp[i][j],dp[j][k] + (t[j] ^ t[i]));
}
}
}
ans = max(ans,dp[i][j]);
}
}
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d",&n);
for(int i = 1; i <= n; i++) {
scanf("%lf %lf",&p[i].x,&p[i].y);
}
sort(p + 1, p + 1 + n, cmp1);
ans = 0;
for(int i = 1; i <= n - 2; i++) { //枚举左下角的起点找最大空凸包
m = 0;
for(int j = i + 1; j <= n; j++) {
t[++m] = p[j] - p[i]; // 以 p[i] 为坐标轴中心,重新定义 p[j]
}
sort(t + 1, t + 1 + m, cmp2);
solve();
}
printf("%.1lf\n",ans / 2.0);
}
return 0;
}