UVA - 1331 Minimax Triangulation (区间dp)(最优三角剖分)
把一个多边形剖分成若干个三角形,使得其中最大的三角形面积最小。
比较经典的一道dp问题
设dp[l][r]为把多边形[l,r]剖分成三角形的最大三角形面积中的最小值,则$dp[l][r]=min\{dp[l][i]+dp[i][r]+area(l,i,r)\}$
注意:
1.由于多边形的点不一定按顺时针或者逆时针排列,需要按点的顺序计算一遍多边形的面积,如果为负说明是顺时针排列,需要反转一下。
2.进行剖分的时候有可能会“出界”,但无需进行线段相交判断,只需在计算的面积出现负数时返回inf即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef double db; 5 const int N=50+10; 6 const db inf=1e18; 7 struct P { 8 db x,y; 9 P operator-(P& b) {return {x-b.x,y-b.y};} 10 } p[N]; 11 db cross(P a,P b) {return a.x*b.y-a.y*b.x;} 12 int n; 13 db calarea() { 14 db ret=0; 15 for(int i=1; i<n-1; ++i)ret+=cross(p[i]-p[0],p[i+1]-p[0]); 16 return ret/2; 17 } 18 db calarea(int l,int m,int r) { 19 return cross(p[l]-p[r],p[m]-p[r])/2; 20 } 21 db d[N][N]; 22 db dp(int l,int r) { 23 if(r-l<2)return 0; 24 db& ret=d[l][r]; 25 if(ret>=0)return ret; 26 ret=inf; 27 for(int i=l+1; i<r; ++i) { 28 db area=calarea(l,i,r); 29 if(area>0)ret=min(ret,max(dp(l,i),max(dp(i,r),area))); 30 } 31 return ret; 32 } 33 34 int main() { 35 int T; 36 for(scanf("%d",&T); T--;) { 37 scanf("%d",&n); 38 for(int i=0; i<n; ++i)scanf("%lf%lf",&p[i].x,&p[i].y); 39 if(calarea()<0)reverse(p,p+n); 40 memset(d,200,sizeof d); 41 printf("%.1f\n",dp(0,n-1)); 42 } 43 return 0; 44 }