欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【算法竞赛入门经典】多阶段决策问题 例题9-5 UVa12563

程序员文章站 2022-06-06 17:28:15
...

【算法竞赛入门经典】多阶段决策问题 例题9-5 UVa12563

例题UVa12563

【算法竞赛入门经典】多阶段决策问题 例题9-5 UVa12563

Input

【算法竞赛入门经典】多阶段决策问题 例题9-5 UVa12563

Output

【算法竞赛入门经典】多阶段决策问题 例题9-5 UVa12563

Sample Input

2
3 100
60 70 80
3 100
30 69 70

Sample Output

Case 1: 2 758
Case 2: 3 777

分析

这是一个0-1背包问题,但是和普通的0-1背包不同的是,他有两个决策条件
决策条件1:相同时间内唱的歌曲要尽量多
决策条件2:满足决策条件1的同时,唱歌的时长要尽量多
鉴于此,有两种做法
Tip:本处所有的方法均利用了滚动数组优化了空间,因此只需要d[j]表示第j分钟时的情况【这也导致了分钟j必须从后往前扫描】
方法1:只记录d[j]表示第j分钟时,最多能唱歌的数目
因为仅仅记录了歌曲的数目,实际上没有办法判定你实际能够唱多长时间的歌。因此,为了知道自己唱了多久的歌曲,应该只允许前j分钟填满的情况出现,即除了最后一段,之前不允许存在空1秒的情况,这样的话,d[j]的值等于最大歌曲数目的那一个j值就是实际唱了多少分钟。这用

if((j==tim[i])||dp[j-tim[i]]>0){
    dp[j]=max(dp[j],dp[j-tim[i]]+1);
    num=max(num,dp[j]);
}

来保证。
为了避免这样麻烦的情况出现,不如新增加一个数组dpt来记录实际能够唱歌的时间。这样就有了方法二
方法2:最多曲目和时间都记录
由于决策条件2制于决策条件1,dpt数组的更改必须严格满足新的条件下,dp[j]的值大于或等于最大曲目数量。只有满足这个条件才最dpt数组进行更新操作。

样例实现代码

第一种:只记录最大曲目

#include<iostream>
#include<cstring>
#include<cmath>
#define maxn 50+5
#define maxt 10000
using namespace std;
int tim[maxn],dp[maxt];
int main(){
    int n,t,T,kase=0;
    cin>>T;
    while(T--){
        cin>>n>>t;
        int num=0;
        for(int i=1;i<=n;i++)
            cin>>tim[i];
        memset(dp,0,sizeof(dp));
        t--;
        for(int i=1;i<=n;i++){
            for(int j=t;j>=tim[i];j--){
                if((j==tim[i])||dp[j-tim[i]]>0){
                    dp[j]=max(dp[j],dp[j-tim[i]]+1);
                    num=max(num,dp[j]);
                }
            }
        }
        int j=t;
        for(;dp[j]!=num;j--);
        if(num==0)
            cout<<"Case "<<++kase<<": "<<num+1<<" "<<678<<endl;
        else
            cout<<"Case "<<++kase<<": "<<num+1<<" "<<j+678<<endl;
    }
    return 0;
}

第二种:最大曲目和时间都记录

#include<iostream>
#include<cstring>
#include<cmath>
#define maxn 50+5
#define maxt 10000
using namespace std;
int tim[maxn],dp[maxt],dpt[maxt];
int main(){
    int n,t,T,kase=0;
    cin>>T;
    while(T--){
        cin>>n>>t;
        int num=0;
        for(int i=1;i<=n;i++)
            cin>>tim[i];
        memset(dp,0,sizeof(dp));
        memset(dpt,0,sizeof(dpt));
        t--;
        for(int i=1;i<=n;i++){
            for(int j=t;j>=tim[i];j--){
                if(dp[j]<dp[j-tim[i]]+1){
                    dp[j]=dp[j-tim[i]]+1;
                    dpt[j]=dpt[j-tim[i]]+tim[i];
                }
                else if(dp[j]==dp[j-tim[i]]+1)
                    dpt[j]=max(dpt[j],dpt[j-tim[i]]+tim[i]);
            }
        }
        cout<<"Case "<<++kase<<": "<<dp[t]+1<<" "<<dpt[t]+678<<endl;
    }
    return 0;
}

结果

【算法竞赛入门经典】多阶段决策问题 例题9-5 UVa12563
20844486为只记录最大曲目
20845255为都记录