[introduction classic of algorithm competition] example of multistage decision making problem 9-5 UVa12563

Posted by jefrat72 on Tue, 31 Mar 2020 23:02:45 +0200

[introduction classic of algorithm competition] example of multistage decision making problem 9-5 UVa12563

Example UVa12563

Input

Output

Sample Input

2
3 100
60 70 80
3 100
30 69 70

Sample Output

Case 1: 2 758
Case 2: 3 777

Analysis

This is a 0-1 knapsack problem, but unlike the ordinary 0-1 knapsack, it has two decision conditions
Decision condition 1: sing as many songs as possible at the same time
Decision condition 2: when the decision condition 1 is satisfied, the singing time should be as long as possible
In view of this, there are two approaches
Tip: all the methods here use the rolling array to optimize the space, so only d[j] is needed to represent the situation of the j-th minute [which also leads to the fact that the j-th minute must be scanned from the back to the front]
Method 1: record only d[j] for the number of songs that can be sung at the jth minute
Because only the number of songs is recorded, there is no way to determine how long you can actually sing. Therefore, in order to know how long a song has been sung, only the first j minutes should be allowed to fill up, that is, except for the last paragraph, there is no space of 1 second before. In this case, the J value of d[j] equal to the maximum number of songs is the actual number of minutes sung. This use

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

To guarantee.
In order to avoid such trouble, it is better to add a new array dpt to record the actual singing time. So there's a way two
Method 2: record the most tracks and time
Because the decision condition 2 is determined by the decision condition 1, the change of dpt array must strictly meet the new condition, and the value of dp[j] is greater than or equal to the maximum number of tracks. Only when this condition is met can the dpt array be updated.

Sample implementation code

First: only record the largest track

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

The second type: the maximum track and time are recorded

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

Result


20844486 is the maximum track only
20845255 is the capital record