dis(a,b)就是两点之间的距离公式
那么这道题该怎么解呢,.先看数据范围x,y<=1e4,so,18个点两点之间距离最大18*1e4*sqrt(2)<2^18,所以如果跳过的点大于18个点,那么显然一个区间内最多不会跳跃超过17个点
现在我们想知道前i个点跳跃几次在哪跳跃能够达到最小花费,不妨设跳跃点数为j属于[0,17],k表示上一个跳跃点距离i的长度
设dp[i][j]表示前i个点跳跃j次,那么上一个跳跃点为i-k-1,由于消耗了j个跳跃点当中的4个跳跃点,所以状态转移方程为dp[i][j]=min(dp[i-k-1][j-k]+dis(i,i-k-1)-power(2,j-k-1)+power(2,j-1))为什么要减掉power(2,j-k-1)呢,因为在计算dp[i-k-1][j-k]的时候我们加上过power(2,j-k-1)
首先我们来定义一些基本的数组和变量
constexpr int N = 1e5 + 5;
struct node {
double x, y;
};
double dp[N][17];
int P[17];
node a[N];
//i,j,k
//前i个点,有j个点是被跳过的,上一个弯曲点距离点i长度为k,
//i的取值范围是[2, n],j的取值范围是[0,min(i-2,16)],k的取值范围是[1,i-2]
//i能够取2是为了计算dp[2][0],j表示的是被跳过的点,那么第一个点和第i个点不能被跳过,而且任意两个点的最大距离为10^4sqrt(10^4)<2^16
//k取1到i-2是因为i-k-1作为起始跳跃点不能为0,且k为0的话起始跳跃点为i的上一个点,两个点之间无法跳跃
double dis(int x, int y) {
double diss = (a[x].x - a[y].x) * (a[x].x - a[y].x) + (a[x].y - a[y].y) * (a[x].y - a[y].y);
diss = std::sqrt(diss);
return diss;
}
//dis是用来计算两点之间的距离的
接下来我们输入数据
int main() {
int n;
std::cin >> n;
for (int i = 1; i <= n; i++)std::cin >> a[i].x >> a[i].y;
P[0] = 1;
//p是2的次幂
for (int i = 1; i <= 16; i++)P[i] = P[i - 1] * 2;
//由于要计算min值,所以不妨把数组都初始化成一个很大的值
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 16; j++) {
dp[i][j] = 1e18;
}
}
return 0;
}
接下来完成核心代码
int main() {
int n;
std::cin >> n;
for (int i = 1; i <= n; i++)std::cin >> a[i].x >> a[i].y;
P[0] = 1;
for (int i = 1; i <= 16; i++)P[i] = P[i - 1] * 2;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 16; j++) {
dp[i][j] = 1e18;
}
}
//为什么要单独把1拎出来,因为我们之前初始化把dp[1][0]也设成1e18了
//什么时候会用到1,0?当j==0,i==2,i-1=1时,在下面dp[i][j] = dp[i - 1][j]中会用到
dp[1][0] = 0;
for (int i = 2; i <= n; i++) {
for (int j = 0; j <= std::min(i - 2, 16); j++) {
//跳跃点数相同,那就只能是上一个点
dp[i][j] = dp[i - 1][j] + dis(i, i - 1);
for (int k = 1; k <= j && i - k - 1 >= 1; k++) {
dp[i][j] = std::min(dp[i][j], dp[i - k - 1][j - k] + dis(i - k - 1, i) - P[j - k - 1] + P[j - 1]);
}
}
}
double ans = 1e20;
for (int j = 0; j <= 16; j++) {
ans = std::min(ans, dp[n][j]);
}
std::cout << std::fixed << std::setprecision(3) << ans << '\n';
return 0;
}
分别枚举i到j的范围,由于i-1不在状态转移方程的范围内,所以我们要在每一次枚举k之前特殊计算一次dp[i][j]=dp[i-1][j]+dis(i,i-1);
以上就是这道题的详细解答,还需勤加练习