• 【CF838E】 Convex Countour


    【CF838E】 Convex Countour

    首先观察题目的性质

    由于是凸包,因此不自交路径中的一条边((x, y))的两端点只能向与(x)(y)相邻的结点连边。

    举个栗子,若选取了一条边((x, y)),且假设编号从(x)(y)结点已经在一条不自交路径中(不考虑特殊情况),那么向外扩展路径只能连向相邻的点,即只能连边((x+1, y))((x, x+1))((x, y-1))((y-1, y))

    很容易用反证法证明。假设连边((x-2, y)),那么点(x-1)则无法通过一条不与((x, y))((x-2, y))相交的路径与其他点连通。而此题路径要覆盖所有点,即所有点之间连通,则矛盾。因此上述结论成立。

    由于选取的路径每次只能向外扩展一个点,那么此题就变成了区间动态规划问题。

    (f_{l, r, 0/1})表示区间([l, r])的最长路径长度,(0)表示路径终点在(l)(1)表示路径终点在(r)

    那么可以得到

    [f_{l, r, 0}=max{f_{l+1, r, 0}+dis(l, l+1), f_{l+1, r, 1}+dis(l, r)}\f_{l, r, 1}=max{f_{l, r-1, 0}+dis(r, l), f_{l, r-1, 1}+dis(r, r-1)} ]

    且易知(f_{x, x, 0}=f_{x, x, 1}=0)

    此题卡空间,不能开两倍大小,将下标取模后再dp即可

    代码如下

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    const int N=2510;
    struct Point {
    	double x, y;
    	Point(int x=0, int y=0):x(x), y(y){}
    } p[N];
    double dis(Point a, Point b) {
    	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    double f[N][N][2];
    int n;
    
    int main() {
    	scanf("%d", &n);
    	for (int i=0; i<n; i++) {
    		int x, y; scanf("%d%d", &x, &y);
    		p[i]=Point(x, y);
    	}
    	for (int len=2; len<=n; len++)
    		for (int l=0; l<n; l++) {
    			int r=(l+len-1)%n;
    			f[l][r][0]=max(f[(l+1)%n][r][0]+dis(p[l], p[(l+1)%n]), f[(l+1)%n][r][1]+dis(p[l], p[r]));
    			f[l][r][1]=max(f[l][(r-1+n)%n][0]+dis(p[r], p[l]), f[l][(r-1+n)%n][1]+dis(p[r], p[(r-1+n)%n]));
    		}
    	double ans=0;
    	for (int i=0; i<n; i++) ans=max(ans, max(f[i][(i+n-1)%n][0], f[i][(i+n-1)%n][1]));
    	printf("%.10lf", ans);
    	return 0;
    }
    
  • 相关阅读:
    侧滑界面的实现
    Private field 'XXX' is never assigned的解决办法
    android先加载注册页面而不是MainActivity主页面
    每日日报4
    每日日报3
    47 选择排序和插入排序
    计算机启动过程 BIOS MBR等
    ARM中MMU地址转换理解(转)
    深度学习框架 CatBoost 介绍
    预训练词嵌入
  • 原文地址:https://www.cnblogs.com/LiHaozhe/p/11687350.html
Copyright © 2020-2023  润新知