1.题目描述:点击打开链接
2.解题思路:本题属于“最优三角剖分”型的dp,设d(i,j)表示子多边形i,i+1,...,j-1(i<j)的最优解,则不难列出状态转移方程如下:
d(i,j)=min(S(i,j,k),max(d(i,k),d(k,j))|i<k<j);
其中,S(i,j,k)为三角形i-j-k的面积。不过此时需要保证i-j是对角线(唯一的例外是i=0且j=n-1),具体做法是当边i-j不满足条件时直接设为INF,其他部分和凸多边形的情形完全一样。
3.代码:
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<cassert> #include<string> #include<sstream> #include<set> #include<bitset> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<cctype> #include<functional> using namespace std; #define me(s) memset(s,0,sizeof(s)) #define rep(i,n) for(int i=0;i<(n);i++) typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; typedef pair <int, int> P; const double eps=1e-10; int dcmp(double x) { if(fabs(x)<eps)return 0; return x<0?-1:1; } struct Point { double x,y; Point(double x=0,double y=0):x(x),y(y){} }; typedef Point Vector; Vector operator+(const Vector&a,const Vector&b){return Vector(a.x+b.x,a.y+b.y);} Vector operator-(const Vector&a,const Vector&b){return Vector(a.x-b.x,a.y-b.y);} Vector operator*(const Vector&a,double p){return Vector(a.x*p,a.y*p);} bool operator<(const Point&a,const Point&b) { return a.x<b.x||(a.x==b.x&&a.y<b.y); } bool operator==(const Point&a,const Point&b) { return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } double Dot(const Vector&a,const Vector&b){return a.x*b.x+a.y*b.y;} double Cross(const Vector&a,const Vector&b){return a.x*b.y-a.y*b.x;} double Length(Vector a){return sqrt(Dot(a,a));} bool SegmentProperIntersection(const Point&a1,const Point&a2,const Point&b1,const Point&b2) { double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1); double c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1); return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0; } bool OnSegment(const Point&p,const Point&a1,const Point&a2) { return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0; } typedef vector<Point> Polygon; int isPointInPolygon(const Point&p,const Polygon&poly) { int n=poly.size(); int wn=0; for(int i=0;i<n;i++) { const Point&p1=poly[i]; const Point&p2=poly[(i+1)%n]; if(p1==p||p2==p||OnSegment(p,p1,p2))return -1; //在边界上 int k=dcmp(Cross(p2-p1,p-p1)); int d1=dcmp(p1.y-p.y); int d2=dcmp(p2.y-p.y); if(k>0&&d1<=0&&d2>0)wn++; if(k<0&&d2<=0&&d1>0)wn--; } if(wn)return 1; //点在内部 return 0; //点在外部 } bool isDiagnal(const Polygon&poly,int a,int b) { int n=poly.size(); for(int i=0;i<n;i++) if(i!=a&&i!=b&&OnSegment(poly[i],poly[a],poly[b]))return false; //线段中间不能有其他点 for(int i=0;i<n;i++) if(SegmentProperIntersection(poly[i],poly[(i+1)%n],poly[a],poly[b]))return false; //不能和多边形的边规范相交 Point midp=(poly[a]+poly[b])*0.5; return (isPointInPolygon(midp,poly)==1); //整条线段在多边形内 } const double INF=1e9; const int N=100+10; double d[N][N]; double solve(const Polygon&poly) { int n=poly.size(); for(int i=0;i<n;i++) for(int j=0;j<n;j++) d[i][j]=-1; for(int i=n-2;i>=0;i--) for(int j=i+1;j<n;j++) { if(i+1==j)d[i][j]=0; else if(!(i==0&&j==n-1)&&!isDiagnal(poly,i,j)) d[i][j]=INF; else { d[i][j]=INF; for(int k=i+1;k<j;k++) { double m=max(d[i][k],d[k][j]); double area=fabs(Cross(poly[j]-poly[i],poly[k]-poly[i]))/2.0; //三角形i-j-k的面积 m=max(m,area); d[i][j]=min(d[i][j],m); } } } return d[0][n-1]; } int main() { int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); double x,y; Polygon poly; for(int i=0;i<n;i++) { scanf("%lf%lf",&x,&y); poly.push_back(Point(x,y)); } printf("%.1lf\n",solve(poly)); } }