#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double INF=0x3f3f3f3f;
const int maxn=1000;
const double esp=1e-6;
int n,m;
struct point
{
double x;double y;
}d[maxn];
double dp[maxn][maxn];
double area(point a,point b,point c)//平面解析几何里有公式,按照A,B,C的逆时针顺序写,依照行列式的方式可以得到该公式
{
return fabs((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y)) / 2.0 ;
}
bool judge(int a,int b,int c)//判断如果是所圈出的三角形的一条边在凹多边形的外面了,就取消。
{
for(int i=1;i<=m;i++)
{
if(i==a||i==b||i==c) continue;
double s=area(d[i],d[a],d[b])+area(d[i],d[b],d[c])+area(d[i],d[a],d[c]);
if(fabs(s-area(d[a],d[b],d[c]))<esp) return true;
}
return false;
}
int main()
{
scanf("%d",&n);
while(n--)
{
memset(dp,0,sizeof(dp));
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%lf%lf",&d[i].x,&d[i].y);
}
for(int p=2;p<m;p++)//三角形以2为起步长度差,因为是三个顶点
{
for(int l=1;l+p<=m;l++)//依然按照短区间先算的原则再算长区间的原则进行计算
{
dp[l][l+p]=INF;
for(int k=l+1;k<l+p;k++)
{
if(judge(l,k,l+p))
{
continue;
}
dp[l][l+p]=min(dp[l][l+p],max(area(d[l],d[k],d[l+p]),max(dp[l][k],dp[k][l+p])));//最大三角形面积最小的三角剖分
}
}
}
printf("%.1f\n",dp[1][m]);
}
return 0;
}
这种矩阵连乘和三角剖分的问题都是这样的格式,都是三个循环为大格式,第一层为长度差,决定了区间的长短,然后就是
枚举长度和左边界始点,那么根据长度和左边界点就可以知道右边界点,然后枚举左边界和右边界中间的点k,dp[i][j] = min(dp[i][j], max(max(dp[i][k], dp[k][j]), Area(i, k, j)).但是有一个问题,即i,k,j三点围成的三角形是否符合要求,判断的条件即为是否存在除i,k,j三点外的一点位于三角形中,有面积法判断。
稍微难一些的就是这个状态转移方程要理解好怎么弄出来的,接下来的循环要写好。这个题目还有点难度的就是求面积的公式的应用,这个在平面解析几何里是有的,这个在大一解析几何里有学过的,还有就是判断那些不符合的三角形的judge的函数的编写,也就是i-j是不是对角线的判断。难点就这么几个。
UVa 1331
最新推荐文章于 2020-02-23 01:21:19 发布