https://codeforces.com/problemset/problem/1625/C
题目大意:在坐标0到l的数轴上,有n个限速点,每个限速点到下一个限速点之间每个单位长度的速度等于限速,现给出每一个点的坐标di和限速ai,坐标为0处必有一个限速点,现在可以删除不超过k个限速点,问从0到l的最短时间是多少
1<=n<=500;1<=l<=1e5;0<=k<=n-1;1<=ai<=1e4
思路:因为如果我们删除了一个点,那么它后面的距离等于它前一个限速点的限速,而如果再把前一个点删掉,那么这一段的速度又等于另一个点,所以删的每一个点都对后面的点有影响,无法从局部最优推到局部最优,那么只能用动态规划来做。
用dp[i][j]表示前i个点中删除了j个点的最短时间,我们遍历i,遍历j,然后遍历i之前的每一个点jj,如果当前已删除的点的数量>=i之后删除的点的数量i-jj,也就是前jj个点删了0-k个点,那么从前jj个点转移过来的方程就是dp[i][j]=dp[jj][j-(i-jj-1)]+a[jj]*(d[i]-d[jj]),这样便可以枚举到所有可能情况,然后我们在i=n+1的时候维护一下答案的最小值即可
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int a[505], b[505];
int dp[505][505];
int main()
{
int n, l, k;
cin >> n >> l >> k;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
a[n+1] = l;//记录终点的坐标
for (int i = 1; i <= n; i++)
{
scanf("%d", &b[i]);
}
for (int i = 0; i <= n+1; i++)
{
for (int j = 0; j <= n+1; j++)
{
dp[i][j] = 1e9;//要求最小值,所以初始化为极大值
}
}
dp[1][0] = 0;
int ans = 1e9;
for (int i = 2; i <= n+1; i++)
{//当前已选择了i个点,包括起点
for (int j = 0; j<=k; j++)
{//当前已删除的点的数量
for (int jj = 1; jj < i; jj++)
{//遍历已选择的点
if (j >= i - jj - 1)//已删除的点的数量大于等于i后面删除的点的数量
dp[i][j] = min(dp[i][j], dp[jj][j - (i - jj - 1)] + b[jj] * (a[i] - a[jj]));//从未删除的点处转移
}
if (i == n+1)
{//维护最小值
ans = min(ans, dp[i][j]);
}
}
}
printf("%d\n", ans);
return 0;
}