ζ

CF1625C-Road Optimization

    题解

题目大意:一条路可以视为一个一维的坐标轴,起点处的坐标为0。这条路上有一些限速牌,两个相邻限速牌之间的限速为先出现(坐标较小)的那个限速牌的限速。题中的限速(输入的a)指:走一单位长度所需要的时间。现在可以移走最多k个限速牌,问移走这最多k个限速牌后,走完整条路所需要的最少时间为多少。保证输入的第一个坐标为0,而且0处的限速牌不能移除。

虽然这题数据量很小,一看就知道大概率是DP,但状态及转移比较难想,先想了一下能不能贪心。想了想,错误地认为只要一个前缀的最终速度最快,就能保证全局耗时最少,结果写完马上意识到出错了,因为如果一直把前面慢的删掉,如果中途出现了更慢的就没机会删了。

然后才开始想DP。这时已经稍微有了一点想法:令dp[i][j]为:在第i个路标以前的路段删掉j个路标后,从0走到第j个路标所需最短时间。虽然有想法,但想法不成熟,最开始我还在想这个第i个路标的去留应该怎么处理,还专门将各个dp对应的最终速度村了下来以便状态转移,后面才想到:第i个路标以前的路段,跟第i个路标本身是无关的,在更新dp[i][]的时候压根就用不到路标i的限速,路标i的限速只在更新后面的限速时用到。

各个dp[i][j]所对应的后续速度也都是a[i],然后就可以写出状态转移方程了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (i = 1; i <= n; i++)
{
for (j = 0; j < i; j++)
{
dp[i][j] = 2e9;
// t:从坐标在i的前j+1的点开始枚举
for (t = i - (j + 1); t < i; t++)
{
//一共拿掉了j个牌子,从t往后拿掉了i-1-t个牌子,从t往前拿掉了j-(i-1-t)个牌子
if (j - (i - 1 - t) < t || j - (i - 1 - t) == 0)
dp[i][j] = min(dp[i][j], dp[t][j - (i - 1 - t)] + a[t] * (d[i] - d[t]));
}
}
}

完整的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
int dp[505][505], d[505], a[505];
int main()
{
int n, k, l, i, j, t;
scanf("%d%d%d", &n, &l, &k);
for (i = 0; i < n; i++)
scanf("%d", &d[i]);
d[n] = l;
for (i = 0; i < n; i++)
scanf("%d", &a[i]);
for (i = 1; i <= n; i++)
{
for (j = 0; j < i; j++)
{
dp[i][j] = 2e9;
// t:从坐标在i的前j+1的点开始枚举
for (t = i - (j + 1); t < i; t++)
{
//一共拿掉了j个牌子,从t往后拿掉了i-1-t个牌子,从t往前拿掉了j-(i-1-t)个牌子
if (j - (i - 1 - t) < t || j - (i - 1 - t) == 0)
dp[i][j] = min(dp[i][j], dp[t][j - (i - 1 - t)] + a[t] * (d[i] - d[t]));
}
}
}
int res = 2e9;
for (i = 0; i <= k; i++)
res = min(res, dp[n][i]);
printf("%d", res);
return 0;
}

需要注意的是:取最终结果时,取的值不一定是拿掉了k个限速牌的值,比如:如果限速牌的限速一直变快,那么一个限速牌都不应该取走。这里取的dp[i][j]表示“在第i个路标以前的路段恰好删掉j个路标后,从0走到第j个路标所需最短时间”,而不是“在第i个路标以前的路段最多删掉j个路标后,从0走到第j个路标所需最短时间”,选这两个状态的代码写法非常相似,但这可以说是截然不同的两种方法,写的时候也千万要注意不能搞混这两个状态,不然很难看出问题。

页阅读量:  ・  站访问量:  ・  站访客数: