#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
struct node
{
int x, y;
}p[55];
//double dp[100][100];//dp定义i到j最佳方案,最佳面积的最小面积
int calcu(int i, int j)//注意利用坐标进行计算的公式
{
return p[i].x*p[j].y - p[i].y*p[j].x;
}//三角形计算的模板,交叉相乘再相减
double area(int i, int j, int k)
{
return (double)abs(calcu(i, j) + calcu(k, i) + calcu(j, k))/2.0;//注意三角形面积的计算
}
bool judge(int i, int j, int k)
{
double record = area(i, j, k);
for (int ans = 1; ans <= n; ans++)//ans用于判断中间是否存在点
{
if (ans == i || ans == j || ans == k)
continue;
if (record == area(i, j, ans) + area(i, k, ans) + area(j, k, ans))//判断内部是否存在点,是否还可以进行分割
{
return false;
}
}
return true;
}//判断分割方法是否合法,注意合法判断的细节
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> n;
double dp[100][100];
for (int i = 1; i <= n; i++)
{
cin >> p[i].x >> p[i].y;
}
for (int i = 1; i <= n - 2; i++)//对dp进行初始化,每个三角形的面积
{
dp[i][i + 2] = area(i, i + 1, i + 2);
}
for (int len = 3; len < n; len++)//利用中间点进行分割,通过控制长度寻找最佳方案,边界条件细节
{
for (int i = 1; i+len<=n; i++)//进行长度的分割,最优子方案的划分求解
{
int j = i + len ;
dp[i][j] = 0x3f3f3f3f;
for (int k = i+1; k <j; k++)
{
if(judge(i,k,j))
dp[i][j] = min(dp[i][j], max(area(i, k, j), max(dp[i][k], dp[k][j])));//寻找每种分割的最大值中的最小值
}//注意area计算的面积,即两种分割方法中的三角形面积,与两边的最佳方案进行比较
}
}
printf("%.1lf\n", dp[1][n]);
}
getchar();
getchar();
return 0;
}
1、注意易错点!!!三角形一直坐标时计算公式s(a,b)+s(b,c)+s(c,a),注意相应的计算顺序,计算式x与y的交换
2、关键注意理解分割的思想方法,尽量找连续的点进行分割,如图中的v0v3v4v5,以及v0v1v2v3,利用dp[i][j]表示i--j点最佳的子方案,即最大面积的最小值,v0v3v6面积与两边的最佳方案进行比较,找出该分割方案的最佳子方案
3、学会关键的区间dp的思想,i--j之间找k点,不同的区间长度都有相应的最佳方案,首先限定区间长度,算出每种区间长度的最佳子方案,注意运用区间dp思想时,注意控制循环相应的范围,复杂度为n^3,限定范围进行分割