CodeForces - 838E Convex Countour

Solution

因为是凸多边形,当连接两点时,相当于将序列划分为两段,段与段之间不能有连线。

我们要求一顺到底,所以每次的连线,相当于将区间缩小,你会发现只能连区间的两个端点。

这个 D P \mathtt{DP} DP 比较好想,我们令 f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0] [ i , j ] [i,j] [i,j] 区间由 i i i 开始的最长不自交路径, f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1] [ i , j ] [i,j] [i,j] 区间由 j j j ​开始的最长不自交路径:

f [ i ] [ j ] [ 0 ] = max ⁡ ( d ( i , i + 1 ) + f [ i + 1 ] [ j ] [ 0 ] , d ( i , j ) + f [ i + 1 ] [ j ] [ 1 ] ) f[i][j][0]=\max(d(i,i+1)+f[i+1][j][0],d(i,j)+f[i+1][j][1]) f[i][j][0]=max(d(i,i+1)+f[i+1][j][0],d(i,j)+f[i+1][j][1])

f [ i ] [ j ] [ 1 ] = max ⁡ ( d ( j , j − 1 ) + f [ i ] [ j − 1 ] [ 1 ] , d ( j , i ) + f [ i ] [ j − 1 ] [ 0 ] ) f[i][j][1]=\max(d(j,j-1)+f[i][j-1][1],d(j,i)+f[i][j-1][0]) f[i][j][1]=max(d(j,j1)+f[i][j1][1],d(j,i)+f[i][j1][0])

当然我们打算破环为链,然而,,,这题卡空间。

我们算一下: 5000 ∗ 5000 ∗ 2 ∗ 8 / 1024 / 1024 = 380 M B > 250 M B 5000*5000*2*8/1024/1024=380MB>250MB 5000500028/1024/1024=380MB>250MB

不过这题可以优化,其实我们把下标取模就行了,因为每次 D P \mathtt{DP} DP 长度只会增加 1 1 1,所以并不会和之前的状态重合。

最后枚举第一次画的边(肯定连接两个相邻的点)取 max ⁡ \max max 即可。注意 f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0] f [ j ] [ i ] [ 1 ] f[j][i][1] f[j][i][1] 是有区别的。

Code

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;

const int N = 2505;

int n;
double x[N], y[N], f[N][N][2], ans;

int read() {
	int x = 0, f = 1; char s;
	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
	while(s >= '0' && s <= '9') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
	return x * f;
}

double d(const int i, const int j) {
	return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}

int main() {
	n = read();
	for(int i = 0; i < n; ++ i) x[i] = read(), y[i] = read();
	for(int len = 2; len <= n; ++ len)
		for(int i = 0; i < n; ++ i) {
			int j = (i + len - 1) % n;
			f[i][j][0] = max(d(i, (i + 1) % n) + f[(i + 1) % n][j][0], d(i, j) + f[(i + 1) % n][j][1]);
			f[i][j][1] = max(d(i, j) + f[i][(j - 1 + n) % n][0], d((j - 1 + n) % n, j) + f[i][(j - 1 + n) % n][1]);
		}
	for(int i = 0; i < n; ++ i) ans = max(ans, max(f[i][(i - 1 + n) % n][0], f[i][(i + 1) % n][1]));
	printf("%.10f\n", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值