这道题目可以套用0-1背包的模型,其中剩余时长-1就是背包的总容量,而在这些时间内,能唱的最多的歌曲数,就是背包问题的重量
cnt[i][j]的定义就是在时长还剩下j秒的时候,在前i首歌中挑选,最多能够唱几首
但是值得一提的是,这里面还有另外一个权值,就是时长;
即如果能唱的歌曲数相同,挑选时长最大的。
值得一提的是,如果不用去管cnt,只去管能唱的时间长度,那么d[i][j]的定义为,在时长还剩j秒时,在前i首歌中挑选,最多能够唱几首歌。此时的重量,就是时间。
在这道题中遇到的bug是,没有考虑到时间的最大值,将数组开小了
下面是代码
#include<cstdio> #include<algorithm> using namespace std; //d[i][j] j秒内,唱前i首歌,可以唱的最多的时间数 //和0-1背包问题的相似之处在于,歌的时间既是重量又是体积 const int maxn = 102; const int maxt = 10000; int d[maxn][maxt]; int cnt[maxn][maxt]; int num_song; int time_left;//计算在time_left - 1的时间内 int time[maxn];//每一首歌对应的时间 int main() { #ifdef local freopen("input.txt","r",stdin); freopen("out.txt","w",stdout); #endif int T; scanf("%d",&T); for(int i = 0;i < T;i++) { scanf("%d%d",&num_song,&time_left); for(int j = 1;j <= num_song;j++)//弃用0 { scanf("%d",&time[j]); } for(int k = 1;k <= num_song;k++) { for(int j = 0;j <= time_left - 1;j++) { d[k][j] = (k == 1? 0:d[k - 1][j]); cnt[k][j] = (k == 1? 0:cnt[k - 1][j]); if(j >= time[k]) { if(cnt[k][j] < cnt[k - 1][j - time[k]] + 1) { cnt[k][j] = cnt[k - 1][j - time[k]] + 1; d[k][j] = d[k - 1][j - time[k]] +time[k]; } else if(cnt[k][j] == cnt[k - 1][j - time[k]] + 1) { if(d[k][j] < d[k - 1][j - time[k]] +time[k]) { d[k][j] = d[k - 1][j - time[k]] + time[k]; } } } } } printf("Case %d: %d %d\n",i+1,cnt[num_song][time_left - 1] + 1,d[num_song][time_left - 1] + 678); } return 0; }