习题: Convex Countour(DP)
题目
思路
我们注意到题目中有一个不自交的条件,
这个条件很容易的就将一个多边形划分成两个部分,即一个部分不可能向另一个部分连边
这个时候就有点像子问题的转换
设\(dp[l][r][0/1]\),即区间\(l\)到\(r\),终点在\(l\)还是在\(r\)
注意因为是一个多边形,所以这里的\(l\)是可以大于\(r\)的
\(dp[l][r][0/1]\)的状态转移还是比较容易的
就是看上一个部分的哪一个点向其连边即可,
因为我们设的\(dp\)状态中就已经有对终点的规定,所以这个转移实际上是\(O(1)\)而不是\(O(n)\)
代码
#include<iostream>
#include<cmath>
using namespace std;
#define pdd pair<double,double>
#define x first
#define y second
int n;
double dp[2505][2505][2],ans;
/*
区间i~j
终点在0/1:i/j
*/
pdd a[2505];
double operator * (const pdd &a,const pdd &b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i].x>>a[i].y;
for(int len=2;len<=n;len++)
{
for(int i=0;i<n;i++)
{
int j=(i+len-1)%n;
dp[i][j][0]=max(dp[(i+1)%n][j][0]+a[(i+1)%n]*a[i],dp[(i+1)%n][j][1]+a[j]*a[i]);
dp[i][j][1]=max(dp[i][(j-1+n)%n][0]+a[i]*a[j],dp[i][(j-1+n)%n][1]+a[(j-1+n)%n]*a[j]);
}
}
for(int i=0;i<n;i++)
ans=max(ans,max(dp[i][(i-1+n)%n][0],dp[i][(i-1+n)%n][1]));
printf("%.13lf",ans);
return 0;
}

浙公网安备 33010602011771号