算法竞赛入门经典 例题9-5

UVa 12563

Jin Ge Jin Qu hao

这题的背景我也是服了。。。

虽然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
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值