咱其实最讨厌图论了 =.= 写这道题简直蛋疼。
给予一个多边形,对其进行三角分割后最大的那个三角形的面积最小值为多少。
像这种肯定是<贪心、DP、搜索>中的一种,贪心么没什么直观的规律用不了,搜索的话虽然多边形的点少(3<=n<=50)但是时间复杂度肯定过不去,后来也想了一下,用记忆化搜索,不过中间状态想不出好方法记录,所以最后想想还是用DP了。
嘛,用DP的时候直接就想成dp[L][R]代表从第L个顶点到第R个顶点的最优分割值,这样的话递推公式也出来了dp[L][R]=min{ max( dp[L][Mid] , dp[Mid][R] , Δ(L,Mid,R) ) , L < Mid < R }(相当于把多边形分割为多边形L~Mid,多边形Mid~R,和一个三角形(L,Mid,R)这样三块)。
考虑到这样分割后都是连续点连成的多边形,可能会漏掉那些非连续的情况。但是后来想了想,连续的情况是可以组成那些非连续的情况的。那就不用加以处理。
恩,这样应该是没问题了,然后交了一发,WA。又不停的改细节,交了5发,全WA。卧槽怎么可能?(╯‵□′)╯︵┻━┻(掀桌)
然后看了下题目的测试例子,可能会出现凹多边形(笑)。
好吧,那就改,怎么改呢。就是排除掉那些违规分割。例如这种:
这种Δ(L,Mid,R) 就是违规分割的,因为其中还包含了其他另外的顶点。那问题就在于判断是否有顶点处于三角形之中,这个用叉积也可以判断就不说了。
我只想说,代码写的简直难看。
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXM = 61;
const int INF = 0x3f3f3f3f;
int dp[MAXM][MAXM];
int Num;
int Clock;
int X[MAXM];
int Y[MAXM];
int Calcu(int a,int b,int c)
{
int x1=X[b]-X[a];
int x2=X[c]-X[a];
int y1=Y[b]-Y[a];
int y2=Y[c]-Y[a];
return Clock*(x1*y2-y1*x2);
}
void Judge()
{
int sum=0;
Clock=1;
for(int i=2;i<Num;i++)
{
sum+=Calcu(1,i,i+1);
}
if(sum<0)Clock=-1;
}
void Read_Case()
{
scanf("%d",&Num);
for(int i=1;i<=Num;i++)
{
scanf("%d %d",X+i,Y+i);
}
}
bool Edge(int a,int b,int c)
{
int i;
int ans=abs((int)Calcu(a,b,c));
for(i=1;i<=Num;i++)
{
if(i==a||i==b||i==c)continue;
if(ans==abs((int)Calcu(i,b,c))+abs((int)Calcu(i,b,a))+abs((int)Calcu(i,a,c)))break;
}
if(i>Num)return 0;
return 1;
}
void Deal()
{
for(int i=1;i<=Num;i++)dp[i][i]=0;
for(int i=1;i<Num;i++)dp[i][i+1]=0;
for(int i=1;i<=Num-2;i++)
{
dp[i][i+2]=Calcu(i,i+1,i+2);
}
int R,L,Mid,Limit,Ans;
for(int dis=3;dis<Num;dis++)
{
Limit=Num-dis;
for(L=1;L<=Limit;L++)
{
R=L+dis;
dp[L][R]=INF;
for(Mid=L;Mid<=R;Mid++)
{
if(Edge(L,Mid,R))continue;
Ans=max(Calcu(L,Mid,R),max(dp[L][Mid],dp[Mid][R]));
dp[L][R]=min(dp[L][R],Ans);
}
}
}
printf("%.1lf\n",dp[1][Num]/2.0);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
Read_Case();
Judge();
Deal();
}
}
要死要死 什么东西扯个图上来就想老半天 = =