学习C++从娃娃抓起!记录下在学而思小猴编程学习过程中的题目,记录每一个瞬间。侵权即删,谢谢支持!
附上汇总贴:小猴编程C++ | 汇总-CSDN博客
积木大赛2
【题目描述】
新一年的积木大赛又要开始了,这次的规则和以前正好相反。先给每位小朋友一座已经建好的宽度为
n
n
n的大厦,要求小朋友将大厦拆除。大厦可以看成由
n
n
n块宽度为
1
1
1的积木组成,第
i
i
i块积木的高度是
h
i
h_i
hi。
每次操作,小朋友们可以选择一段不包含高度为
0
0
0积木的连续区间
[
L
,
R
]
[L,R]
[L,R],然后将第
L
L
L块到第
R
R
R块之间(含第
L
L
L块和第
R
R
R块)所有积木的高度分别减少
1
1
1。最终目标是将所有积木的高度都变成
0
0
0。
经过去年的比赛,大家都知道了最佳策略。小明为了在比赛中获得优势,学会了一种魔法:他可以在比赛开始前,选择最多
k
k
k块积木,任意修改它们的高度(不能修改成负数),使用魔法不记操作次数。
通过在比赛开始前使用魔法,小明拆除积木需要的最小操作次数是多少?
【输入】
第
1
1
1行,
2
2
2个整数
n
,
k
n,k
n,k
第
2
2
2行,
n
n
n个整数
h
1
,
h
2
,
…
,
h
n
h_1,h_2,\dots,h_n
h1,h2,…,hn
【输出】
输出小明需要的最少操作次数。
【输入样例】
4 1
2 3 4 1
【输出样例】
3
【代码详解】
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 305;
int n, k, h[N];
LL f[N][N];
int main()
{
cin >> n >> k;
memset(f, 0x3f, sizeof(f)); // 初始化为最大值(因为要求最小值)
f[0][0]=0; // 递推式初始条件
for (int i=1; i<=n; i++) cin >> h[i]; // 输入n块积木的高度
if (n==k) { // 特判n==k时,可以删除n块积木
cout << 0 << endl; // 最小操作次数就是0
return 0;
}
for (int i=1; i<=n-k; i++) { // 留下积木数,从1 - n-k
for (int j=1; j<=n; j++) { // 当前最后一块留下的积木编号,从1 - n
for (int x=0; x<j; x++) { // 之前留下的最后一块积木编号,从0 - j-1
f[j][i] = min(f[j][i], f[x][i-1]+max(0, h[j]-h[x])); // 比较求最小值,f[x][i-1]表示之前留下的最后一块积木x,以及少留1块积木的操作次数,加上上一块是x,当前是j的贡献值(操作次数)
}
}
}
LL ans = 1e18;
for (int i=1; i<=n; i++) { // 留下n-k积木时,哪块积木作为最后一块积木的最小值
ans = min(ans, f[i][n-k]);
}
cout << ans << endl; // 输出答案
return 0;
}
【运行结果】
4 1
2 3 4 1
3