UVA 12563 Jin Ge Jin Qu hao(01背包变形:两个条件最优化)

题意:

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;
}

在这里插入图片描述

发布了33 篇原创文章 · 获赞 2 · 访问量 1090

猜你喜欢

转载自blog.csdn.net/qq_44954571/article/details/105443719