【UVA1331】关于最优三角剖分
来源:互联网 发布:人工智能的主要技术 编辑:程序博客网 时间:2024/06/07 06:32
题目提交地址:https://cn.vjudge.net/problem/UVA-1331
##第一篇题解##
最优三角剖分的一类题目都是差不多的。给你一个多边形,让你把它分割成若干个三角形,求三角形某最优解,比如UVA1331要求面积最大的三角形的面积最小。如图是各种切割方法:
不知道一开始看到最大值最小化会不会又一下子想到枚举答案二分去了呢,不过本题正解是DP。
然而,这题最难的地方不是推出递推方程,而是表示状态。因为如果允许随意切割,则“半成品”多边形的各个定点是可以在原多边形中随意选取的。这就是我一直在纠结的一个问题,比如下面的第一张图(除起始点和结束点,相邻的点编号都是连续的):
一共有4条边,我们可以以随意的顺序切割,不过如果这样的话,就会出现类似v0v3v4v6这样的多边形,这样的多边形很难用简洁的状态表示出来,这就是让我一开始很纠结的地方。
其实我们会发现,对于同一种切割方法,我们可以有多种切割顺序,但我们只要计算一种就好了,不如把决策顺序规范化。例如还是上面第一张图,我们可以先切割出三角形v0v3v6,那么我们切割完之后可以把图分割成一个三角形和两个多边形,而组成这两个个多边形的点的编号都是连续的。
于是我们可以得出一种切割方法,比如我要切割多边形i,i+1,...,j-1,j(i<j),那么我下一步切割的三角形一定有i和j这两个点(这样的规定并不会出错,因为无论我们如何切割,分出来的三角形中一定有一个过i和j),而这样的切割方法的优点是保证了每次切出来的多边形组成的点的编号都是连续的,于是我们就可以用两个元素表示一个多边形的状态了,这样dp转移方程很容易可以得出来:
d(i,j)=min{max(d(i,k),d(k,j),S(i,j,k))|i<k<j};
其中,S(i,j,k)为三角形i-j-k的面积。不过此时需要保证i-j是对角线(唯一的例外是i=0且j=n-1),具体做法是当边i-j不满足条件时直接设为INF,其他部分和凸多边形的情形完全一样。
代码如下:
#include<cstdio>#include<cstdlib>#define INF 0xfffffffconst int Maxm=50+5;int m;int x[Maxm],y[Maxm];double d[Maxm][Maxm];double area(int a,int b,int c){ double s=(double)(1.0/2)*(x[a]*y[b]+x[b]*y[c]+x[c]*y[a]-x[a]*y[c]-x[b]*y[a]-x[c]*y[b]); if(s<0) return -s; return s;}double mymin(double a,double b) {return a<b?a:b;}double mymax(double a,double b) {return a>b?a:b;}bool check(int a,int b,int c){ int i; for(i=1;i<=m;i++) { if(i==a||i==b||i==c) continue; double d=area(a,b,i)+area(a,c,i)+area(b,c,i)-area(a,b,c); if(d<0) d=-d; if(d<=0.01) return 0; } return 1;}int main(){ int n; scanf("%d",&n); while(n--) { int i,j,k; scanf("%d",&m); for(i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]); for(i=m;i>=1;i--) { d[i][i+1]=0.0; for(j=i+2;j<=m;j++) { d[i][j]=INF; for(k=i+1;k<j;k++) { if(check(i,j,k)) d[i][j]=mymin(d[i][j],mymax(mymax(area(i,j,k),d[i][k]),d[k][j])); } } } printf("%.1lf\n",d[1][m]); }}
##第二篇题解##
博客地址: http://blog.csdn.net/c20190102/article/details/75418824
将一个多边形用它不相交的对角线将它分成若干个三角形,使得最大的三角形面积最小,求最大三角形的面积。如图是一个六边形的几种剖分:
思路
记由点u,u+1,…,v-1,v(u< v)组成的多边形为
首先,总的多边形为
对于
设d[i][j]表示
状态转移方程:
这样就完了吗?不是的,还有一个问题:
当
所以怎么判断
换个思路,判断
怎么判断点是否在
“面积法”是很好的办法:设现在枚举到的点为
#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define MAXN 50#define INF 0x7fffffff#define eps 0.0001struct point{ double x,y;}p[MAXN+5];//点int N;double d[MAXN+5][MAXN+5];//动归double dis(int x,int y){return sqrt((p[x].x-p[y].x)*(p[x].x-p[y].x)+(p[x].y-p[y].y)*(p[x].y-p[y].y));}//计算两点距离double area(int x,int y,int z)//计算由点x,y,z构成的三角形的面积(海伦公式){ double a=dis(x,y),b=dis(y,z),c=dis(x,z); double p=(a+b+c)/2; return sqrt(p*(p-a)*(p-b)*(p-c));}bool check(int x,int y,int z)//判断由点x,y,z构成的三角形中有没有点{ double tarea=area(x,y,z); for(int i=1;i<=N;i++) { if(i==x||i==y||i==z) continue; double a=area(i,x,y),b=area(i,y,z),c=area(i,x,z); if(fabs(a+b+c-tarea)<eps)//double计算有精度误差,不要用== return 0; } return 1;}int main(){ int T; scanf("%d",&T); while(T--) { scanf("%d",&N); for(int i=1;i<=N;i++) scanf("%lf%lf",&p[i].x,&p[i].y); for(int i=N-2;i>=1;i--) for(int j=i+2;j<=N;j++) { d[i][j]=INF; for(int k=i+1;k<j;k++)//选择分割点 if(check(i,j,k)) d[i][j]=min(d[i][j],max(area(i,j,k),max(d[i][k],d[k][j]))); } printf("%.1lf\n",d[1][N]); memset(d,0,sizeof(d)); }}
- 【UVA1331】关于最优三角剖分
- uva1331最优三角形剖分
- 例题9-11 UVa1331 Minimax Triangulation(DP:最优三角剖分)
- 最优三角剖分
- 最优三角剖分
- 最优三角剖分
- 凸多边形最优三角剖分
- 凸多边形最优三角剖分
- 凸多边形最优三角剖分
- 凸多边形最优三角剖分
- 凸多边形最优三角剖分
- 凸多边形最优三角剖分
- 例题9-11 最大面积的最小的三角剖分 UVa1331
- 凸多边形最优三角剖分问题
- 凸多边形的最优三角剖分问题
- dp 最优三角剖分问题
- 入门经典 最优三角剖分
- 【动态规划】凸多边形最优三角剖分
- 文件IO方式操作GPIO
- 两个字符串是否存在相同部分的比较
- tensorflow检查op是否可导(反向传播)
- 庆科信息AZ3166亮相北京2017微软技术暨生态大会
- opengl入门
- 【UVA1331】关于最优三角剖分
- 单据开发时,怎样让字段是添加时间的值是当前的时间?
- 基于Spring、SpringMVC、MyBatis、Druid、Shrio构建web系统
- python 最大公约数与最小公倍数
- Android 手机号,密码正则验证
- apache对目录和地址的安全权限控制
- 用Java进行动态公式处理
- maven打包时去除不需要的jar包策略
- MySQL存储过程实例——实现查询数据表,有则更新无则插入