习题: 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;
}
posted @ 2020-07-29 10:21  loney_s  阅读(156)  评论(0)    收藏  举报