題目:
http://acm.swust.edu.cn/#/problem/195/490
題目描述
哆啦A夢班級舉辦個party,當然喫的東西必不可少,哆啦A夢負責採購任務,他得到了一份清單,上面註明不同食品的受歡迎程度,哆啦A夢需要用一定的價錢儘可能達到的更大的受歡迎程度!例如,瓜子的受歡迎程度爲20,瓜子的價錢是50元,那麼如果哆啦A夢選擇買瓜子,將花費50元,但受歡迎程度增加了20。爲了避免食品單調性,每種食品只能買一份,不能重複購買。 現在哆啦A夢需要知道如何採購才能達到最大的受歡迎程度,你能幫助他嗎?
輸入
輸入數據爲多組,每組輸入的第一行有兩個正整數M和N(M<100&&N<1000),分別爲哆啦A夢可以支配的錢數和清單上的可選擇的物品種類。 接下來的N行每行有兩個正整數,分別爲每種物品的價錢和它的受歡迎程度(編號爲1到N)。
輸出
如果存在物品購買,那麼輸出的第一行爲能夠達到的最大的受歡迎程度。第二行爲需要購買的物品的編號(如果有多種可能,輸出字典序靠前的那種),空格分隔每個數字;如沒有物品可以購買,輸出只有一行,爲數字0。
樣例輸入
10 4
100 5
5 5
5 5
10 10
樣例輸出
10
2 3
說明:
因爲求具體的方案,我們就不能採取之前滾動數組優化版本的 01揹包 ,因爲這樣會損失一些具體方案
因爲要求字典序最小,那麼我們肯定採取貪心策略(能選序號小的就選序號小的)
我們如果從前往後遍歷所有的物品,那麼最後 dp[n][m] 就是最後答案,那我們就得從後往前遍歷纔可以求的具體方案 ,但是這樣所求的是字典序最大的
所以我們應該反一下,從後往前去遍歷所有物品,這樣dp[1][m]就是最後答案,那麼我們就從前往後遍歷就可以求具體方案,這樣求的是字典序最小的
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int maxm=105;
int m,n;
int w[maxn],v[maxn],dp[maxn][maxm];
void solve(){
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++){
dp[i][j]=0;
}
}
for(int i=1;i<=n;i++){
cin>>w[i]>>v[i];
}
for(int i=n;i>=1;i--){
for(int j=1;j<=m;j++){
if(j>=w[i]){
dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
}else{
dp[i][j]=dp[i+1][j];
}
}
}
if(dp[1][m]){
cout<<dp[1][m]<<endl;
}else{
cout<<0<<endl;
}
}
void print(){
int s=m,t=0;
/**
care for the print form
**/
for(int i=1;i<=n;i++){
if(s-w[i]>=0&&dp[i][s]==dp[i+1][s-w[i]]+v[i]){
s-=w[i];
t++;
}
}
s=m;
for(int i=1;i<=n;i++){
if(s-w[i]>=0&&dp[i][s]==dp[i+1][s-w[i]]+v[i]){
s-=w[i];
t--;
if(t!=0) cout<<i<<" ";
else cout<<i<<endl;
}
}
}
int main(){
while(cin>>m>>n){
solve();
print();
}
return 0;
}