题目描述
N N N 座楼立于城市,排成一列。 第 i i i 座楼,高度 H i H_i Hi 。
你需要一开始选择一个座楼,开始跳楼。在第 i i i 座楼准备跳跃需要 C i C_i Ci 的花费。每次可以跳到任何一个还没有跳过的楼上去。但跳跃是有代价的,每次跳到另外一座楼的代价是两座楼高度的差的绝对值,最后一次从楼跳到地面上不需要代价(只能跳到地上一次)。
问:在代价不超过 T T T 的情况下,最多跳跃几次?(一座楼只能跳一次,且每次跳跃都要计算准备的花费)。
输入格式
第一行一个整数
N
N
N,代表楼的数量。
接下来一行
N
N
N 个整数代表
C
i
C_i
Ci。
接下来一行
N
N
N 个整数代表
H
i
H_i
Hi。
最后一行一个整数
T
T
T。
输出格式
一行一个整数代表答案。
样例
样例输入1:
4
3 5 4 11
2 1 3 1
17
样例输出1:
3
样例解释1
从
1
1
1 号楼跳到
2
2
2 号楼再跳到
3
3
3 号楼是一种可行的方案。
数据范围
对于
30
%
30\%
30% 的数据,
1
≤
N
≤
5
1 \le N \le 5
1≤N≤5。
对于另外
20
%
20\%
20% 的数据,所有
H
i
H_i
Hi 相同。
对于另外
20
%
20\%
20% 的数据,
C
i
=
0
C_i = 0
Ci=0。
对于
100
%
100\%
100% 的数据,
1
≤
N
≤
50
,
1
≤
C
i
,
H
i
≤
1
0
6
,
1
≤
T
≤
1
0
7
1 \le N \le 50, 1 \le C_i, H_i \le 10^6, 1 \le T \le 10^7
1≤N≤50,1≤Ci,Hi≤106,1≤T≤107。
题解
首先,从地面跳到楼,要跳到较低的,后面选出的也要不递减。
证明:
假设我们已经选出了
m
m
m 座楼,每座楼的高度为
H
i
H_i
Hi,代价为
C
i
C_i
Ci,且
H
i
≥
H
i
−
1
H_i \ge H_{i - 1}
Hi≥Hi−1。
此时的代价为:
C
1
+
…
+
C
m
+
∣
H
1
∣
+
∣
H
2
−
H
1
∣
+
…
+
∣
H
m
−
H
m
−
1
∣
①
C_1 + \ldots + C_m + |H_1| + |H_2 - H_1| + \ldots + |H_m - H_{m - 1}|①
C1+…+Cm+∣H1∣+∣H2−H1∣+…+∣Hm−Hm−1∣①。
化简得到:
C
1
+
…
+
C
m
+
H
m
C_1 + \ldots + C_m + H_m
C1+…+Cm+Hm。
交换
i
i
i 和
i
+
1
i + 1
i+1 座楼,代价为
C
1
+
…
+
C
m
+
∣
H
1
∣
+
∣
H
2
−
H
1
∣
+
…
+
∣
H
i
+
1
−
H
i
−
1
+
∣
H
i
+
2
−
H
i
∣
+
…
+
∣
H
m
−
H
m
−
1
∣
②
C_1 + \ldots + C_m + |H_1| + |H_2 - H_1| + \ldots + |H_{i + 1} - H_{i - 1} + |H_{i + 2} - H_{i}| + \ldots + |H_m - H_{m - 1}|②
C1+…+Cm+∣H1∣+∣H2−H1∣+…+∣Hi+1−Hi−1+∣Hi+2−Hi∣+…+∣Hm−Hm−1∣②。
①
−
②
① - ②
①−②,得到交换前和交换后的代价之差:
∣
H
i
−
H
i
−
1
∣
+
∣
H
i
+
2
−
H
i
+
1
∣
−
∣
H
i
+
1
−
H
i
−
1
∣
−
∣
H
i
+
2
−
H
i
∣
|H_{i} - H_{i - 1}| + |H_{i + 2} - H_{i + 1}| - |H_{i + 1} - H_{i - 1}| - |H_{i + 2} - H_{i}|
∣Hi−Hi−1∣+∣Hi+2−Hi+1∣−∣Hi+1−Hi−1∣−∣Hi+2−Hi∣。
由于
∣
H
i
−
H
i
−
1
∣
≤
∣
H
i
+
1
−
H
i
−
1
∣
,
∣
H
i
+
2
−
H
i
+
1
∣
≤
∣
H
i
+
2
−
H
i
∣
|H_{i} - H_{i - 1}| \le |H_{i + 1} - H_{i - 1}|,|H_{i + 2} - H_{i + 1}| \le |H_{i + 2} - H_{i}|
∣Hi−Hi−1∣≤∣Hi+1−Hi−1∣,∣Hi+2−Hi+1∣≤∣Hi+2−Hi∣,所以交换前和交换后的代价之差小于
0
0
0,所以交换后更优。
因此,从小到大排序更优。
接下来如果贪心的话,应该很难想到怎么写。
考虑使用 dp
算法,
d
p
i
,
j
dp_{i, j}
dpi,j 表示跳到第
i
i
i 座楼时已经跳了
j
j
j 次的最小代价。
转移方程很好想,
d
p
i
,
j
=
min
(
d
p
k
,
j
−
1
+
∣
h
i
−
h
k
∣
+
c
i
,
d
p
i
,
j
)
{
j
−
1
≤
k
≤
n
}
dp_{i, j} = \min(dp_{k, j - 1} + |h_i - h_k| + c_i, dp_{i, j})\{j - 1 \le k \le n\}
dpi,j=min(dpk,j−1+∣hi−hk∣+ci,dpi,j){j−1≤k≤n}。
即要跳到第
i
i
i 座楼已经跳了
j
j
j 次,可以从前面的楼跳过来。
代码:
int n, m;
struct node{
int x, y;//c, h
}a[60];
bool cmp(node p, node q){
y 从小到大排序
}
int dp[60][60];
int main(){
输入,排序
memset(dp, 0x7f, sizeof(dp));
int ans = 0;
//初始化
for(int i = 1; i <= n; ++ i){
dp[i][1] = a[i].x;
if(dp[i][1] <= m){
ans = max(ans, 1);
}
}
for(int i = 1; i <= n; ++ i){//第 i 座楼
for(int j = 2; j <= i; ++ j){//跳了 j 座楼
for(int k = 0; k < i; ++ k){//从第 k 座楼转移
dp[i][j] = min(dp[i][j], dp[k][j - 1] + abs(a[i].y - a[k].y) + a[i].x);
}
if(dp[i][j] <= m){
ans = max(ans, j);
}
}
}
输出 ans
}