12563 - Jin Ge Jin Qu hao(DP)

自己花了两个小时A出来的感觉就是不一样啊,学习DP建议大家多煎熬一点,好好思考状态是如何转移的。

不过这道题我一开始理解错题意了,不然也不会浪费这么长时间 。 一开始以为是背包问题,后来才发现要求使得唱的曲目尽量多,在此前提下尽量晚离开KTV,我恰好弄颠倒了。

这样我们就不难得出递推方程 : 因为每首曲目只能唱一遍,所以这就使递推变得有序了~ 那么我们设cnt[i][j]表示唱前i首歌中的若干,且总时间不超过j 的最大歌曲数目 。

那么cnt[i][j] = max(cnt[i-1][j],cnt[i-1][j-a[i]] + 1);    因为还要使总时间尽量长,所以当cnt[i][j] == cnt[i-1][j-a[i]] + 1 时,d[i][j] = max(d[i][j],d[i-1][j-a[i]] + a[i]);

细节参见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 55;
int T,n,t,Case = 0,d[maxn][180*maxn + 678],a[maxn],cnt[maxn][180*maxn + 678];
int main() {
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&t);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++) {
            for(int j=0;j<=t;j++) {
                cnt[i][j] = (i == 1 ? 0 : cnt[i-1][j]);
                d[i][j] = (i == 1 ? 0 : d[i-1][j]);
                if(j > a[i]) {
                    if(cnt[i][j] < cnt[i-1][j-a[i]] + 1) {
                        cnt[i][j] = cnt[i-1][j-a[i]] + 1;
                        d[i][j] = d[i-1][j-a[i]] + a[i];
                    }
                    else if(cnt[i][j] == cnt[i-1][j-a[i]] + 1) {
                        d[i][j] = max(d[i][j],d[i-1][j-a[i]] + a[i]);
                    }
                }
            }
        }
        printf("Case %d: %d %d\n",++Case,cnt[n][t]+1,d[n][t]+678);
    }
    return 0;
}


你可能感兴趣的:(ACM,uva)