ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF838E Convex Countour(动态规划)

2020-03-17 14:00:26  阅读:337  来源: 互联网

标签:路径 Countour 个点 max Convex vertices CF838E path dis


Description

You are given an strictly convex polygon with n vertices. It is guaranteed that no three points are collinear. You would like to take a maximum non intersecting path on the polygon vertices that visits each point at most once.

More specifically your path can be represented as some sequence of distinct polygon vertices. Your path is the straight line segments between adjacent vertices in order. These segments are not allowed to touch or intersect each other except at the vertices in your sequence.

Given the polygon, print the maximum length non-intersecting path that visits each point at most once.

Input

The first line of input will contain a single integer nn ( 2<=n<=2500), the number of points.

The next n lines will contain two integers xi​,yi​ (∣xi​∣,∣yi​∣≤109), denoting the coordinates of the i-th vertex.

It is guaranteed that these points are listed in clockwise order.

Output

Print a single floating point number, representing the longest non-intersecting path that visits the vertices at most once.

Your answer will be accepted if it has absolute or relative error at most 10-910^{-9}
. More specifically, if your answer is aa and the jury answer is bb , your answer will be accepted if  $\frac{|a-b|}{max(1,b)}$≤$10^{-9}$.

题目大意

按顺时针给出一个凸多边形,任意两点间有一条直线边,求经过每个点恰好一次的最长不自交路径。

Solution

首先,我们可以注意到,如果从 i 点连线到 j 点,则所有的点被分为两份之间不可以连线。

而对于其中一份,我们必须从 i 点或 j 点出发,按题目要求经过其中的每个点。

不妨设我们现在考虑的是第 i+1 个点到第 j-1 个点,从 i 点出发。

可以发现,我们只有两个选择:

  • 连到 i+1,并以该点为起点经过 i+2 到 j-1.
  • 连到 j-1,并以该点为起点经过 i+1 到 j-2.

其他情况类似,注意特殊考虑区间跨过 1 号点与 n 号点的情况。

由此,我们可以这样进行dp:

状态:f[i][j] 表示经过第 i 个点到第 j 个点的所有点恰好一次的不自交路径中,以第 i 个点为起点的最长路径。g[i][j] 表示经过第 i 个点到第 j 个点间的所有点恰好一次的不自交路径中,以第 j 个点为起点的最长路径。

转移:f[i][j]=max(dis(i,i+1)+f[i+1][j],dis(i,j)+g[i+1][j])

g[i][j]=max(dis(i,j)+f[i][j-1],dis(j-1,j)+g[i][j-1])

有一个小技巧,可以将环形的信息转化成长度为两倍的链,这样环形的问题就变成了线形的问题。

但是,对于这道题,如果转化为长度两倍的链,那么空间就变为原来的4倍,这将会导致算法常数大大增大。

我们观察到,f[i][j] 只从区间长度是 i-j 的状态转移而来,所以我们可以改一下状态的定义,使得可以使用滚动数组。

定义:f[i][j] 表示经过第 i 个点到第 i+j 个点间的所有点恰好一次的不自交路径中,以第 i 个点为起点的最长路径。g[i][j] 表示经过第 i 个点到第 i+j 个点间的所有点恰好一次的不自交路径中,以第 i+j 个点为起点的最长路径。

转移:f[i][j]=max(dis(i,i+1)+f[i+1][j-1],dis(i,i+j)+g[i+1][j-1])

g[i][j]=max(dis(i,i+j)+f[i][j-1],dis(i+j-1,i+j)+g[i][j-1])

这样,把第二维设为外层阶段,并利用循环数组进行优化,即可省下空间。

code

代码中,f[0]、g[0] 与f[1]、g[1] 互相滚动。

here

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int N=3010;
 5 int n;
 6 double f[2][N],g[2][N],ans;
 7 struct data{
 8     double x,y;
 9 }a[N];
10 double dis(data x,data y){
11     return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
12 }
13 signed main(){
14     //freopen(".in","r",stdin);
15     //freopen(".out","w",stdout);
16     scanf("%lld",&n);
17     for(int i=0;i<n;i++)
18         scanf("%lf%lf",&a[i].x,&a[i].y);
19     for(int j=1;j<n;j++)
20         for(int i=0;i<n;i++){
21             f[j%2][i]=max(f[(j-1)%2][(i+1)%n]+dis(a[i],a[(i+1)%n]),g[(j-1)%2][(i+j)%n]+dis(a[i],a[(i+j)%n]));
22              g[j%2][i]=max(g[(j-1)%2][(i-1+n)%n]+dis(a[i],a[(i-1+n)%n]),f[(j-1)%2][(i-j+n)%n]+dis(a[i],a[(i-j+n)%n]));
23         }
24     for(int i=0;i<n;i++)
25         ans=max(ans,max(f[(n-1)%2][i],g[(n-1)%2][i]));
26     printf("%.10lf\n",ans);
27     return 0;
28 }

 

标签:路径,Countour,个点,max,Convex,vertices,CF838E,path,dis
来源: https://www.cnblogs.com/maoyiting/p/CF838E.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有