题意:
KTV里面有n首歌曲你可以选择,每首歌曲的时长都给出了. 对于每首歌曲,你最多只能唱1遍. 现在给你一个时间限制t (t<=10^9) , 问你在最多t-1秒的时间内可以唱多少首歌曲num , 且最长唱歌时间是多少time (time必须<=t-1) ? 最终输出num+1 和 time+678 即可.
注意: 你需要优先让歌曲数目最大的情况下,再去选择总时长最长的.
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=180*50+5;
int n,max_t;
int t[50+5]; //每首歌曲的时间
struct Node
{
int num; //总歌曲数
int time;//歌总时间
bool operator<(const Node &rhs)const//判断是否更优
{
return num<rhs.num || (num==rhs.num && time<rhs.time);
}
}dp[maxn];
int main()
{
int T;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
printf("Case %d: ",kase);
scanf("%d%d",&n,&max_t);
memset(dp,0,sizeof(dp));
int sum=0;//所有歌曲总时长
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
sum +=t[i];
}
//max_t是我们最大需要考虑的时间
max_t = min(sum,max_t-1);
//注意max_t==sum和max_t==0时的情况.
for(int i=1;i<=n;i++)
{
for(int j=max_t;j>=t[i];j--)//1
{
Node tmp;//tmp表示当选择第i首歌时的情况
tmp.num = dp[j-t[i]].num+1;//2
tmp.time = dp[j-t[i]].time+t[i];
if(dp[j]<tmp)//tmp更优
{
dp[j]=tmp;//3
}
//这里的1,2,3代码放在一起看,第二句代码表示花费其他时间能唱几首歌,在加上选择第i首歌时能唱几首歌正好是题目给的最大时间。
// 如例题2:第一次循环将dp[30]-dp[99]置为一,表示30-99分钟能放第一首歌
// 第二次循环将dp[j-t[i]]循环等价于dp[0]-dp[30]在加上现在所花时间69表示区间为69-99正好能唱完时长为69的歌,在加上之前0-30之中能唱几首歌,就是69-99分钟直接能唱几首歌。
//简单来说,就是之前能唱几首歌,加上现在能唱的一首歌,保存在变量dp中
}
}
printf("%d %d\n",dp[max_t].num+1,dp[max_t].time+678);
}
return 0;
}