题目理解
这道题说是简单的烦恼,其实也十分简单。
将题目简单整理一下:
- 你的歌单里有
首歌。
- 歌单里的每一首歌的时长为
,其中
为一个长度为
的序列。
- 你设置了一个
个单位时间的定时关闭。
- 定时关闭时间到达之后,将正在播放的最后一首歌放完后关机。
- 你想使得你听歌曲的时间最长,问最多是多少时间。
- 这题有
组 测试数据。
解法思路
之后,我们来想一想解法:
换作我,如果我想让我所听时间最长,我一定会把那首最长的歌在第 个单位时间(结束前的一刻)让它播放。
这样就可以使得听到时间最长。
所以这个问题被转化为了 “在 个单位时间内,听
首(除去最长的那首)曲子”。
也就是说,
再仔细一想,这不就是一个01背包问题吗?其中背包总容量为 ,共有
件物品,每一件物品的体积和价值都是
。
接着,我们考虑一些细节:
- 这题的每一个测试点都有
组 测试数据,所以如果我们要用动态规划,这个
f[]数组要用memset()清理,同时每一次输出之后要换行,防止出错。 - 我们如何把
首曲子中最长的那一首从数组中除去呢?这里有两种方法:
- 在输入的时候使用两个变量来分别存储最长的歌的长度,和这首歌的下标。然后在循环递推时判断,如果遍历到了那首歌,就直接
continue。
2.将数组a[]直接升序排个序。循环的时候只循环a[1]~a[n-1]最大的那首歌自然就被除去了。
- 在输入的时候使用两个变量来分别存储最长的歌的长度,和这首歌的下标。然后在循环递推时判断,如果遍历到了那首歌,就直接
AC 代码
#include<bits/stdc++.h>
using namespace std;
const int N=80005;
int T;
int n,t;
int a[210];
int f[210][N];
int main(){
cin>>T;
while(T--){
memset(f,0,sizeof(f)); // 多测不清空,爆0两行泪
cin>>n>>t;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n); // 排序
// 二维的01背包
for(int i=1;i<=n-1;i++){
for(int j=0;j<=t-1;j++){
f[i][j]=f[i-1][j];
if(j>=a[i]){
f[i][j]=max(f[i][j],f[i-1][j-a[i]]+a[i]);
}
}
}
cout<<f[n-1][t-1]+a[n]<<endl; // f[n-1][t-1] (t-1个单位时间内的最大值)+ a[n] (最后也是最长的的一首曲子)
}
return 0;
}

京公网安备 11010502036488号