12563 - Jin Ge Jin Qu hao 【DP】

题目大意

传送门

输入n,t(n首歌,剩余t秒)和每首歌的长度。
输出可以唱的最多的总歌曲数目
以及
唱歌的时间长度。

样例

input

2

3 100
60 70 80

3 100
30 69 70

output

Case 1: 2 758
Case 2: 3 777

解释

第一个样例中,两首歌:80 + 678 = 758
第二个样例中 ,三首歌:30 + 69 + 678 = 777

思路

就是一个简单的01背包,不过有两个状态需要记录,而且这两个状态之间是有关系的。
在满足唱的曲目最多的条件下,时间最长。
所以状态转移方程是这样的:

for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= t; j++){
                    dp[i][j][0] = dp[i - 1][j][0];
                    dp[i][j][1] = dp[i - 1][j][1];
                    if (j >= w[i])
                    {
                        if (dp[i][j][0] < dp[i - 1][j - w[i]][0] + 1)//首先考虑唱的曲目最多
                        {
                            dp[i][j][0] = dp[i - 1][j - w[i]][0] + 1;
                            dp[i][j][1] = dp[i - 1][j - w[i]][1] + w[i];
                        }
                        else if (dp[i][j][0] == dp[i - 1][j - w[i]][0] + 1){//曲目相等的情况下才考虑时间
                            dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j - w[i]][1] + w[i]);
                        }

                    }
                }
            }

代码

#include <stdio.h>
#include <cstring>
#define max(a,b) (a>b)? a:b
#define min(a,b) (a<b)? a:b 

#define MAXN 55
#define MAXT 10000

int n, t;
int w[MAXN];
int dp[MAXN][MAXT][2];//在第i层,时间为t的时候,能唱的最多的歌曲数目



int main()
{
    int CaseNum,kase;
    scanf("%d", &CaseNum);
    for (int kase = 1; kase <= CaseNum; kase++)
    {
        scanf("%d %d", &n, &t);
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; i++) scanf("%d", &w[i]);


            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= t; j++){
                    dp[i][j][0] = dp[i - 1][j][0];
                    dp[i][j][1] = dp[i - 1][j][1];
                    if (j >= w[i])
                    {
                        if (dp[i][j][0] < dp[i - 1][j - w[i]][0] + 1)
                        {
                            dp[i][j][0] = dp[i - 1][j - w[i]][0] + 1;
                            dp[i][j][1] = dp[i - 1][j - w[i]][1] + w[i];
                        }
                        else if (dp[i][j][0] == dp[i - 1][j - w[i]][0] + 1){
                            dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j - w[i]][1] + w[i]);
                        }

                    }
                }
            }

            printf("Case %d: %d %d\n", kase, dp[n][t - 1][0] + 1, dp[n][t - 1][1]+678);
    }
}

/*
Sample Input
100

3 100
60 70 80

3 100
30 69 70

13 747
78 90 50 31 89 137 78 52 87 96 128 163 92

16 780
47 70 119 33 67 74 62 120 162 175 7 111 92 100 18 42

44 1311
151 91 13 21 23 164 105 127 126 47 145 52 140 95 57 112 171 168 113 127 83 78 17 175 130 130 146 59 68 49 138 150 179 98 80 9 142 38 128 151 60 9 61 81

Sample Output
Case 1: 2 758
Case 2: 3 777
Case 3: 11 1421
Case 4: 13 1455
Case 5: 24 1987

*/

Hit

这两个状态转移的过程一定是有关系的,容易犯的错误就是分开考虑

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值