[dp]跳跃

题目描述

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 1N5
对于另外 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 1N50,1Ci,Hi106,1T107

题解

首先,从地面跳到楼,要跳到较低的,后面选出的也要不递减。
证明
假设我们已经选出了 m m m 座楼,每座楼的高度为 H i H_i Hi,代价为 C i C_i Ci,且 H i ≥ H i − 1 H_i \ge H_{i - 1} HiHi1
此时的代价为: 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+H2H1++HmHm1∣①
化简得到: 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+H2H1++Hi+1Hi1+Hi+2Hi++HmHm1∣②
① − ② ① - ② ,得到交换前和交换后的代价之差: ∣ 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}| HiHi1+Hi+2Hi+1Hi+1Hi1Hi+2Hi
由于 ∣ 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}| HiHi1Hi+1Hi1,Hi+2Hi+1Hi+2Hi,所以交换前和交换后的代价之差小于 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,j1+hihk+ci,dpi,j){j1kn}
即要跳到第 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
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值