UVa 12563
这题的背景我也是服了。。。
虽然KTV没少去,但是我真的没发现还有这种骚操作:时间到了之后是不会立即播放《拒绝黄赌毒》的,而是可以把这首歌唱完。如果选择唱一首《劲歌金曲》(并不是jin),那么就能多唱10
分钟,所以你可以算算在所剩不多的时间t
里,最多还能唱几首,以及最多还能唱多长时间。
这是一个背包问题,可以简述为有n
首歌,每首歌只能唱1
次,要求在所剩不多的t
秒内,唱尽可能多的歌,同时唱得尽可能的长。这样即使最后只剩1
秒,点一首超长的就能多唱好久。😃😃
按照给定歌曲的顺序,依次决定要不要唱这首歌就好了。如果不唱,总数目不变,总时间也不变;如果唱,会用掉一定的时间,对后面的选择有影响,所以应该把时间也考虑进来,因此用sung[s][t]
表示已经对第s
首歌进行了选择,同时用掉的时间为t
时能唱的最大数目,递推公式为sung[s][t] = max(sung[s - 1][t], sung[s - 1][t - len[s]] + 1)
,前一项表示不唱,后一项表示唱。
因为这道题还要求出实际唱歌时间,并且在唱得一样多的情况下唱得尽可能得长,即在决定唱,虽然不能多唱但是可以延长时间的情况下更新实际唱歌时间。
#include <iostream>
#include <vector>
using namespace std;
void findMaximumSung(const vector<int> &viLength, const int time)
{
size_t song = viLength.size();
vector<vector<pair<int, int>>> sung(viLength.size(), vector<pair<int, int>>(time, make_pair<int, int>(0, 0)));
for (int t = viLength[0]; t < time; t++)
{
sung[0][t].first = 1;
sung[0][t].second = viLength[0];
}
for (size_t s = 1; s < song; s++)
{
for (int t = 0; t < time; t++)
{
sung[s][t] = sung[s - 1][t];
if (t >= viLength[s]) {
if (sung[s][t].first < sung[s - 1][t - viLength[s]].first + 1) {
sung[s][t].first = sung[s - 1][t - viLength[s]].first + 1;
sung[s][t].second = sung[s - 1][t - viLength[s]].second + viLength[s];
}
else if (sung[s][t].first == sung[s - 1][t - viLength[s]].first + 1) {
if (sung[s][t].second < sung[s - 1][t - viLength[s]].second + viLength[s]) {
sung[s][t].second = sung[s - 1][t - viLength[s]].second + viLength[s];
}
}
}
}
}
int maxTime = 0, maxSung = 0;
for (size_t t = time; t > 0; t--)
{
if (sung[song - 1][t - 1].first > maxSung) {
maxSung = sung[song - 1][t - 1].first;
maxTime = sung[song - 1][t - 1].second;
}
else if (sung[song - 1][t - 1].first == maxSung) {
if (sung[song - 1][t - 1].second > maxTime) {
maxTime = sung[song - 1][t - 1].second;
}
}
}
cout << maxSung + 1 << ' ' << maxTime + 678 << endl;
}
int main()
{
int Test, n, t;
cin >> Test;
for (int test = 0; test < Test; test++)
{
cin >> n >> t;
vector<int> viLength(n, 0);
for (int song = 0; song < n; song++)
{
cin >> viLength[song];
}
cout << "Case " << test + 1 << ": ";
findMaximumSung(viLength, t);
}
return 0;
}
/*
2
3 100
60 70 80
3 100
30 69 70
*/