作者:〢ヽ夜╰︶ ̄太美
链接:https://www.nowcoder.com/discuss/486642?type=2
来源:牛客网
题意
有n(n在5000内)块木板,宽度是1,长度不固定,这些小木板拼接起来一块大木板。
给一个宽度为1的刷子,每刷一次可以选择横着刷和竖着刷,过程中都不能离开木板。
问最少要刷几次能把木板完全刷一遍。
做法
动态规划题,dp[i][j]dp[i][j]dp[i][j]表示当前完全刷完了前iii块木板,横着刷的部分能延伸到之后木板的部分高度为jjj的最小代价,显然jjj不会超过nnn,因为所有木板竖着刷答案就是nnn了,不存在横着刷高度超过nnn的情况。
我们枚举所有的状态,转移情况如下:
-
竖着刷
此时代价是1,能延伸的部分是jjj和当前木板高度取最小值。
-
横着刷
如果当前木板高度小于jjj,则没有代价,否则要补上他们之间的差值,能延伸的部分是当前木板的高度。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 7;
int dp[N][N];
int a[N];
int main() {
memset(dp, 0x3f, sizeof dp);
dp[0][0] = 0;
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
for(int i = 0; i < n; i++)for(int j = 0; j <= n; j++) {
int high;
//竖着刷
high = min(j, a[i + 1]);
dp[i + 1][high] = min(dp[i + 1][high], dp[i][j] + 1);
//横着刷
if(a[i + 1] < n) {
if(j >= a[i + 1])dp[i + 1][a[i + 1]] = min(dp[i + 1][a[i + 1]], dp[i][j]);
else dp[i + 1][a[i + 1]] = min(dp[i + 1][a[i + 1]], dp[i][j] + a[i + 1] - j);
}
}
int ans = n;
for(int i = 0; i <= n; i++)ans = min(dp[n][i], ans);
printf("%d\n", ans);
return 0;
}