【dp - 01揹包求方案】195: Buyer

題目:
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章