完整代碼
東東開車出去泡妞(在夢中),車內提供了 n 張CD唱片,已知東東開車的時間是 n 分鐘,他該如何去選擇唱片去消磨這無聊的時間呢
假設:
CD數量不超過20張
沒有一張CD唱片超過 N 分鐘
每張唱片只能聽一次
唱片的播放長度爲整數
N 也是整數
我們需要找到最能消磨時間的唱片數量,並按使用順序輸出答案(必須是聽完唱片,不能有唱片沒聽完卻到了下車時間的情況發生)
Input
多組輸入
每行輸入第一個數字N, 代表總時間,第二個數字 M 代表有 M 張唱片,後面緊跟 M 個數字,代表每張唱片的時長 例如樣例一: N=5, M=3, 第一張唱片爲 1 分鐘, 第二張唱片 3 分鐘, 第三張 4 分鐘
所有數據均滿足以下條件:
N≤10000
M≤20
Output
輸出所有唱片的時長和總時長,具體輸出格式見樣例
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揹包相比,多了一個回溯過程,要求得到放到揹包中的物體。本題輸出可能會有多種形式,輸出任意一種即可。比如最後一組數據,可能會輸出43 2 sum:45。
回溯過程的實現就是考慮當前dp[x][y],如果dp[x][y]=dp[x-1][y],那就說明沒有選擇第x個物品,回溯x-1, y。如果dp[x][y]=dp[x-1][y-w[i]]+v[i],那麼就說明選擇了第x件物品,回溯x-1, y-w[i]。直到x和y有一方爲0就返回。
完整代碼
//#pragma GCC optimize(2)
//#pragma G++ optimize(2)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn=20+1;
const int maxm=10000+1;
int n,m,a[maxn],dp[maxn][maxm];
int getint(){
int x=0,s=1; char ch=' ';
while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}
while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}
return x*s;
}
void find(int x,int y){//回溯
if(x==0 || y==0) return;
if(dp[x][y]==dp[x-1][y])//第x件物品沒有選擇
find(x-1,y);
else if(dp[x][y]==dp[x-1][y-a[x]]+a[x]){//選擇了
find(x-1,y-a[x]);
printf("%d ",a[x]);
}
}
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
while(cin>>n>>m){
for (int i=1; i<=m; i++)
cin>>a[i];
for (int i=1; i<=m; i++)//普通01
for (int j=0; j<=n; j++){
if(j>=a[i]) dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+a[i]);
else dp[i][j]=dp[i-1][j];
}
find(m,n);
printf("sum:%d\n",dp[m][n]);
memset(dp,0,sizeof(dp));
}
return 0;
}