这道题可以用DP来做,实质上是个背包模型,因为它有一个费用t。
状态:dp[i,j]表示前i首歌,在j分钟内可以听的歌曲的总时长。
状态转移方程:
dp[i,j]=
if(j<song[i]) dp[i-1,j];
else max(dp[i-1,j],dp[i-1,j-song[i]]+song[i]);
在这里要注意一下:因为我们要选出最接近时间t的歌曲的时间总和sum(不能>=t),然后sum+max(song[i]),这样才可以使时间最长。因此j的范围是[song[i],t-1]。
这里的j和dp[i,j]所表示的意义都是时间,说明背包中DP对象以及DP意义的物理意义是可以一样——其实只要有费用,就可以想到用背包模型来做。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
typedef long long ll;
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=8e4+5;
int dp[maxn],s[205]; //用了滚动数组
int main()
{
int T,n,t,i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&t);
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
scanf("%d",&s[i]);
sort(s+1,s+1+n);
dp[0]=0;
for(i=1;i<=n-1;i++) //i止于n-1
for(j=t-1;j>=s[i];j--)
dp[j]=max(dp[j],dp[j-s[i]]+s[i]);
printf("%d\n",dp[t-1]+s[n]);
}
return 0;
}