UVA12563
定义:dp[i][j]为考虑前i首歌并且总时长为j时最多能唱的歌曲数,Song[i]表示第i首歌的时长。
转移方程:
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
S
o
n
g
[
i
]
]
+
1
)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-Song[i]]+1)
dp[i][j]=max(dp[i−1][j],dp[i−1][j−Song[i]]+1)
经典的01背包。
题目特殊要求在注释中说明。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
int n, T;
int Song[51], dp[51][10001];
void Input() {
cin >> n >> T;
for (int i = 1; i <= n; ++i) {
cin >> Song[i];
}
}
void DP() {
memset(dp, 0x8f, sizeof(dp));
for (int i = 0; i <= n; ++i) {
dp[i][0] = 0;
}
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < Song[i]; ++j) {
dp[i][j] = dp[i - 1][j];
}
for (int j = Song[i]; j <= T; ++j) {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - Song[i]] + 1);
}
}
}
void Output(const int&Case) {
//枚举dp[n][j],找出最多的歌曲数,由于要留1秒给《劲歌金曲》,所以从T-1开始枚举。
//由于要逗留最长时间,所以时间从大到小枚举,知道遇到第一个歌曲数对应的时间点
int Ans = T - 1;
for (int j = T - 1; j >= 0; j--) {
if (dp[n][j] > dp[n][Ans]) {
Ans = j;
}
}
printf("Case %d: %d %d\n", Case, dp[n][Ans] + 1, Ans + 678);
}
int main() {
int T;
cin >> T;
for (int Case = 1; Case <= T; ++Case) {
Input();
DP();
Output(Case);
}
return 0;
}
PS:可以优化成一维数组,但是嘛,怎么方便怎么来233333