题意:

输入
输出:

样例:
输入:
5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2
输出:
1 4 sum:5
8 2 sum:10
10 5 4 sum:19
10 23 1 2 3 4 5 7 sum:55
4 10 12 9 8 2 sum:45
思路:
即背包问题,其中每张唱碟的为一种物品,唱碟的时间同时为物品的重量和价值,求能满足的最大的价值。不过在其中要记录下选取最大价值的是哪些物品。在这里用了一个vis[i][j]的数组,表示在第i轮时容积为j的时候,即判断到前i个物品的时候的是否选取,如果选取了则记录为。之后从满背包的时候,依次往回判断,如果第i个物品选取了,背包容量减少a[i]。然后i–,即判断上一个是否选取了。直到所有的i的状态和j的状态判断结束。
代码:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
int N,M; //总时间,总的唱片的数量 N<=10000 M<=20
int a[25];
int f[10050]; //记录总花费时间
int b[25]; //记录已选择的点
int vis[25][10050]; //记录该点是否选择
int main(){
ios::sync_with_stdio(0);
while(cin>>N>>M){
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
for(int i=1; i<=M; i++){
cin>>a[i];
}
for(int i=1;i<=M;i++){
for(int j=N;j>=0;j--){
if(j-a[i]>=0){
if(f[j]<=f[j-a[i]]+a[i]){
f[j]=f[j-a[i]]+a[i];
vis[i][j]=1; //在i,j情况下选择了当前的点
}
}
}
}
int i=M,j=N,tot=0;
while(i>=1 && j>=0){
if(vis[i][j]){
j=j-a[i]; //减去当前已经存好的点
b[++tot]=a[i];
}
i--; //每一轮是否选择的
}
for(int i=tot;i>=1;i--)
cout<<b[i]<<" ";
cout<<"sum:"<<f[N]<<endl;
}
return 0;
}