You have a long drive by car ahead. You have a tape recorder, but unfortunately your best music is on CDs. You need to have it on tapes so the problem to solve is: you have a tape N minutes long. How to choose tracks from CD to get most out of tape space and have as short unused space as possible
Assumptions:
• number of tracks on the CD does not exceed 20
• no track is longer than N minutes
• tracks do not repeat
• length of each track is expressed as an integer number
• N is also integer Program should find the set of tracks which fills the tape best and print it in the same sequence as the tracks are stored on the CD
Input:
Any number of lines. Each one contains value N, (after space) number of tracks and durations of the tracks. For example from first line in sample data: N = 5, number of tracks=3, first track lasts for 1 minute, second one 3 minutes, next one 4 minutes
Output :
Set of tracks (and durations) which are the correct solutions and string ‘sum:’ and sum of duration times.
Sample Input:
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
Sample Output:
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
思路:
本题是典型的01背包问题,但要考虑记忆化搜索,对选择的物品要用一个数组来储存他是否选择。
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,T,t[100000],dp[30][100000],ap[30][100000]={0},a[100000];
ap表示是否选择该物品
while(scanf("%d%d",&T,&n)!=EOF){
for(int i=1;i<=n;i++)cin>>t[i];
for(int i=1;i<n;i++)dp[i][0]=0;//初始化
for(int j=0;j<=T;j++){
dp[0][j]=0;
ap[0][j]=1;//初始化0件物品时,容量为j值为1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=T;j++){
ap[i][j]=0;
if(j<t[i])dp[i][j]=dp[i-1][j];
else{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-t[i]]+t[i]);
if(dp[i-1][j]!=dp[i][j])ap[i][j]=1;//选择第i件物品
}
}
}
int maxvalue=dp[n][T];
int cnt=0;
for(int i=n,j=T;i>=1;i--){
if(ap[i][j]==1){
a[cnt]=t[i];
cnt++;
j-=t[i];
}
}//从容量为T开始找,如果ap为1则减掉该物品的容积。
for(int i=cnt-1;i>=0;i--)printf("%d ",a[i]);
printf("sum:%d\n",maxvalue);
}
return 0;
}