洛谷 CF838E Convex Countour
考虑“除了路径序列中的顶点外,这些线段不能相交或接触”是什么意思。画一下图:

路径不能出现如上图的交叉。再天马行空地画几种合法的路径:


只要稍加观察就会发现,第一张图中的路径一定不会是答案,因为 \(1\rightarrow 8\rightarrow 6\) 优于 \(1\rightarrow 6\),同时 \(8\rightarrow 7\rightarrow 6\) 优于 \(8\rightarrow 6\)。而对于第二张图中的路径,貌似就不太能找到显然优于它的。
进一步地,我们发现 最优的路径一定会经过多边形的所有顶点。不妨再以上面两张合法的图为例。在第一张图中,蓝色路径没有经过点 \(7,8\),又因为路径不能相交,所以外面的点(\(2,3,4,5\))也不能与 \(7,8\) 连。由于三角形两边之和大于第三边,所以 \(1\rightarrow 6\) 一定劣于 \(1\rightarrow 8 \rightarrow 7\rightarrow 6\)。第二张图就没有类似的问题。
因为要经过所有的点恰好一次,再画一画就知道不可能出现下面的情况:

走 \(1\rightarrow 3\rightarrow 6\),到 \(6\) 之后,无论往左还是往右,之后都不能覆盖另一边的所有点。要避免这种情况,只能在从 \(i\) 走到 \(j\) 后,下一步走到与 \(i\) 或 \(j\) 相邻的点。
所以最优路径中,已经经过的所有点是连续的,且每次只能向外扩展 \(1\) 个位置。因此断环成链,设计区间 DP:状态需要区分路径方向,设 \(dp_{l,r,0/1}\) 表示区间 \([l,r]\) 内的答案,且 \(l/r\) 为终点。初始 \(dp_{i,i,0}=dp_{i,i,1}=0\),有转移
最终答案为
然而 \(5000\times 5000\times 2\) 的 double 数组爆了空间。需要换一种状态设计:设 \(dp_{len,l,0/1}\) 表示区间长度为 \(len\),左端点为 \(l\) 且 \(l\) 为终点/起点时,\([l,r]\) 内的答案。转移是类似的。由于求 \(dp_{len}\) 只需要 \(dp_{len-1}\) 和坐标,所以可以滚动数组优化。时间复杂度 \(\mathcal{O}(n^2)\),空间复杂度 \(\mathcal{O}(n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
bool Mbegin;
void File_Work(){
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
}
typedef double Ld;
const int N=5e3+8;
int n;
Ld xx[N],yy[N],dp[2][N][2];
Ld get_dis(int i,int j){
return sqrt((xx[i]-xx[j])*(xx[i]-xx[j])+(yy[i]-yy[j])*(yy[i]-yy[j]));
}
void MAIN(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>xx[i]>>yy[i];
xx[i+n]=xx[i],yy[i+n]=yy[i];
}
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n*2;l++){
int r=l+len-1;
dp[len&1][l][0]=max(dp[!(len&1)][l+1][0]+get_dis(l,l+1),dp[!(len&1)][l+1][1]+get_dis(l,r));
dp[len&1][l][1]=max(dp[!(len&1)][l][1]+get_dis(r-1,r),dp[!(len&1)][l][0]+get_dis(l,r));
}
}
Ld ans=0;
for(int l=1;l<=n;l++)
ans=max({ans,dp[n&1][l][0],dp[n&1][l][1]});
cout<<fixed<<setprecision(10)<<ans;
}
bool Mend;
int main(){
// File_Work();
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cerr<<fixed<<setprecision(3)<<(&Mbegin-&Mend)/1048576.0<<" MB\n\n\n";
int testid,testnum=1;
// cin>>testid;
// cin>>testnum;
while(testnum--)
MAIN();
cerr<<"\n\n\n"<<fixed<<setprecision(0)<<1e3*clock()/CLOCKS_PER_SEC<<" ms";
return 0;
}

浙公网安备 33010602011771号