PTA團體程序設計天梯賽-練習集 L3-001 湊零錢(01揹包問題)

韓梅梅喜歡滿宇宙到處逛街。現在她逛到了一家火星店裏,發現這家店有個特別的規矩:你可以用任何星球的硬幣付錢,但是絕不找零,當然也不能欠債。韓梅梅手邊有104枚來自各個星球的硬幣,需要請你幫她盤算一下,是否可能精確湊出要付的款額。

輸入格式:

輸入第一行給出兩個正整數:N(<=104)是硬幣的總個數,M(<=102)是韓梅梅要付的款額。第二行給出N枚硬幣的正整數面值。數字間以空格分隔。

輸出格式:

在一行中輸出硬幣的面值 V1 <= V2 <= … <= Vk,滿足條件 V1 + V2 + … + Vk = M。數字間以1個空格分隔,行首尾不得有多餘空格。若解不唯一,則輸出最小序列。若無解,則輸出“No Solution”。

注:我們說序列{A[1], A[2], …}比{B[1], B[2], …}“小”,是指存在 k >= 1 使得 A[i]=B[i] 對所有 i < k 成立,並且 A[k] < B[k]。

輸入樣例1:
8 9
5 9 8 7 2 3 4 1
輸出樣例1:
1 3 5
輸入樣例2:
4 8
7 2 4 3
輸出樣例2:
No Solution
分析:01揹包問題,因爲要輸出從小到大的排列,可以先把硬幣面額從大到小排列,然後用bool類型的choice[i][j]數組dp[i][j]是否選取,如果選取了就令choice爲true;然後進行01揹包問題求解,如果最後求解的結果不是恰好等於所需要的價值的,就輸出No Soultion,否則從choice[i][j]判斷選取的情況,i從n到1表示從後往前看第i個物品的選取情況,j從m到0表示從容量m到0是否選取(j = j – w[i]),把選取情況壓入arr數組中,最後輸出arr數組

#include <bits/stdc++.h>
using namespace std;
int dp[10010];
int w[10010];
bool choice[10010][10010];
bool cmp(int a,int b){return a > b;}
int main() {
	int n,m;
	cin>>n>>m;
	for(int i = 1;i <= n;i++){
		cin>>w[i];
	}
	sort(w + 1,w + n + 1,cmp);
	for(int i = 1;i <= n;i++){
		for(int j = m;j >= w[i];j--){
			if(dp[j] <= dp[j - w[i]] + w[i]){
				choice[i][j] = true;
				dp[j] = dp[j - w[i]] + w[i];
			}
		}
	}
	vector<int> res;
	if(dp[m] != m) cout<<"No Solution"<<endl;
	else{
		int v = m, index = n;
        while(v > 0) {
            if(choice[index][v] == true) {
                res.push_back(w[index]);
                v -= w[index];
            }
            index--;
        }
        for(int i = 0;i < res.size();i++) {
            if(i != 0) cout<<" ";
            cout<<res[i];
        }
	}
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章