#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,a[105],pre[105][10005],dp[10005],ans[10005],top;
inline void print(int m,int n){
    if(m<=0||n<=0)return;
    if(pre[m][n]==1){
        ans[++top]=a[m];
        print(m-1,n-a[m]);
    }else print(m-1,n);
}
int main(){
    while(scanf("%d %d",&n,&m)!=EOF){
        top=0;
        memset(a,0,sizeof(a));
        memset(pre,0,sizeof(pre));
        memset(dp,0,sizeof(dp)); 
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=m;i++)scanf("%d",&a[i]);
        for(int i=1;i<=m;i++){
            for(int j=n;j>=a[i];j--){
                if(dp[j-a[i]]+a[i]>dp[j]){
                    pre[i][j]=1;
                    dp[j]=dp[j-a[i]]+a[i];
                }
            }
        }
        print(m,n);
        for(int i=top;i>=1;i--)printf("%d ",ans[i]);
        printf("sum:%d\n",dp[n]);
    }
    return 0;
}

一道简单的01背包,输出sum的数值十分简单,就不多赘余。

然而对于输出序列,主要思路与输出最大上升子序列一致。

首先,我们可以使用一个pre二维数组来存储状态。
如果pre[i][j]等于1,则表示当前CD已选择,自然,是说前i张CD进行j分钟时选择了该CD。

反之pre[i][j]等于0,则未进行选择……

最后递归输出选择CD序列,详见print函数,如若选择,继续递归前i-1个CD,进行了j-a[i]分钟,建议用一个ans数组进行存储。

最后逆序输出!!!