劲歌金曲(子集型动规)

Description

  如果问一个麦霸:“你在KTV里必唱的曲目有那些?”得到的回答通常包含一首“神曲”――古巨基的《劲歌经典》。为什么呢?一般说来,KTV不会在“时间到”的时候鲁莽地把正在唱的歌切掉,而是会等它放完。例如,在还有15秒时再唱一首2分钟的歌,则实际上多唱了105秒。但是融合了37首歌曲的《劲歌经典》长达11分18秒,如果唱这首歌,相当于多唱了663秒。

  假定你正在唱KTV,还剩下t秒时间。你决定下来只唱你最爱的n首歌(不含《劲歌经典》)中的一些,在时间结束之前再唱一个《劲歌金曲》,使得唱的总曲目尽量多(包含《劲歌经典》),在此前提下尽量晚的离开KTV。

Input

  第一行为在整数T,表示测试数据组数。  每组测试数据占两行,第一行为整数n和t,分别表示n首歌曲和你还剩下的时间为t秒。第二行为n个整数,分别表示n首的时长(保证不超过3分钟)。  输入保证所有n+1首歌曲的总长度严格大于t。

Output

  每组数据输出一行,包含两个整数,分别表示你还能唱的曲目的最多数目和最大的总时长。

01背包问题,只是注意统计答案时不要把f[t]也算进去,因为此时总时间已到,不能唱额外的一首了。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int MAXN=55;
const int MAXT=9005;
const int ADD=678;
const int INF=200000000;
int T,N,TI,f[MAXT],t[MAXN],sum[MAXN];
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&N,&TI);
		
		int ans=0,num=0;
		for(int i=1;i<=N;i++)
		{
			scanf("%d",&t[i]);
			sum[i]=sum[i-1]+t[i];
		}
		
		for(int i=1;i<=9000;i++)
			f[i]=-INF;
			
		f[0]=0;
		for(int i=1;i<=N;i++)
		for(int j=min(TI-1,sum[i]);j>=t[i];j--)
			f[j]=max(f[j],f[j-t[i]]+1);

		for(int i=min(TI-1,sum[N]);i>=0;i--)
		{
			if(f[i]>num)
			{
				num=f[i];
				ans=i;
			}
			else if(f[i]==num)
				ans=max(ans,i);
		}
		
		printf("%d %d",num+1,ans+ADD);
		if(T) printf("\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/81155711