题目大意:给你n个点围城的多边形,顺时针或者逆时针给你,起始点任意,让你把他划成n-2个三角形,这些划法中最大的三角形的面积最小,输出这个最小值。
思路:按照区间长度进行DP。对于 i~j 这些点,考虑新加入的点是j,那么就多了两条弦 i~j,j-1 ~j,对于 i~j 这条弦,加进去,它能围成的是 Aea2(i,k,j),i<k<j,,此时最大的三角形是 max( Area2( i , k , j ) ,dp[ i ][ k ] ,dp[ k ][ j ] ),dp[ i ][ j ] 表示按照题目给的方向来的 i ~ j 的最小的面积,对于这些又取最小,就是dp[ i ][ j ] = min(max( Area2( i , k , j ) ,dp[ i ][ k ] ,dp[ k ][ j ] ),dp[ i ][ j ]),i<k<j,而同时,j - 1~j它围成的已经在dp[ k ][ j ] 之中包含了, 综合起来就是上面那个式子,长度从4开始DP,初始化为长度3的,为了统一,要把长度1、2的变成0,。这里还有一个关键的地方,那就是 Area2( i , k , j) 的时候,它有可能是凹多边形,要判断有没有出界,这个时候只要枚举除这三个点的全部的点,用面积和看看他们中间有没有点就行了。
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string.h>
using namespace std;
#define EPS 1e-8
#define Max 55
const int INF = (1 << 30);
int n;
double dp[Max][Max];
struct Point
{
int x;
int y;
}p[Max];
int Area2(Point p2, Point p3, Point p1)
{
int temp = (p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y);
return temp;
}
int check(int a, int b, int c) //判断是否出界
{
int area = fabs(Area2(p[a], p[b], p[c]));
for (int i = 0; i < n; i++)
{
if (i == a || i == b || i == c)
{
continue;
}
int temp = fabs(Area2(p[a], p[b], p[i]))
+ fabs(Area2(p[a], p[c], p[i])) + fabs(Area2(p[b], p[c], p[i]));
if (temp == area)
{
return 0;
}
}
return 1;
}
int main()
{
freopen("E:\input.txt", "r", stdin);
int num;
scanf("%d", &num);
while (num--)
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d%d", &p[i].x, &p[i].y);
}
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
{
dp[i][(i + 2) % n] = fabs(Area2(p[i], p[(i + 1) % n], p[(i + 2) % n]));
}
for(int len = 3;len<=n;len++)
{
for(int i = 0;i<n;i++)
{
int j = (i + len)%n;
dp[i][j] = INF;
for(int k = (i+1)%n; k!= j; k = (k+1)%n)
{
if(check(i,k,j)) dp[i][j] = min(dp[i][j],max(max(dp[i][k],dp[k][j]),fabs(Area2(p[i],p[k],p[j]))));
}
//printf("i = %d,j = %d,d = %f\n",i,j,d[i][j]);
}
}
double ans = INF;
for(int i = 0;i<n;i++)
ans = min(dp[i][(i+n-1)%n],ans);
printf("%.1f\n",ans/2);
}
return 0;
}
参考Blog:
UVALive 3132 Minimax Triangulation
poj 2066
ACM: 计算几何题 poj 2066