1. 程式人生 > >qdu yzm10與大富翁的故事 (01揹包+輸出路徑)

qdu yzm10與大富翁的故事 (01揹包+輸出路徑)

yzm10與大富翁的故事

Description

 

這款《大富翁》遊戲曾經是我的啟蒙桌遊之一,印象最深的就是那一疊疊花花綠綠的鈔票,還有和小夥伴從歡樂買地到撕逼掀桌的搞笑回憶~

當你的對手在一整條街上開滿了旅館(經過時要交過路費),每一次擲骰子都會心驚膽戰,一不小心就會損失一個億的感覺(╯▔皿▔)╯。

最近在逛桌遊店的時候,我又忍不住上前搓了一把。

yzm10與大富翁的故事.jpg

在購買地產、繳納地稅或交過路費時,往往需要支付一定的金額,我們需要用手中的鈔票組合出恰好能支付金額的錢數,滿足a[1]+a[2]+...+a[k]=M。

眼下我又來到了死亡一條街...看著小夥伴得意洋洋的樣子,我心有不甘地拿出了鈔票。

當然了支付時還是有一定技巧的,在選擇面值時,儘可能選大額的鈔票,這樣就可以保證剩下足夠多的零錢,有更多的金額組合形式,從而減少了不必要的浪費。這裡你只需保證讓最小的面值儘可能大即可。

現在告訴你初始時yzm10手裡各張鈔票的面值,你能猜出他是怎麼支付的嗎?

Input

 

第一行給出兩個正整數:N(1<=N<=10^4)是yzm10手中的鈔票數,M(1<=M<=100)是需要支付的金額。

第二行給出N張鈔票的非負整數面值(保證在int範圍內),數字間以空格分隔。

Output

 

在一行中按升序輸出所需支付的各張鈔票的面值,保證讓最小的面值儘可能大,數字間以空格分隔。

若無法恰好湊出金額(不足或浪費),則輸出-1。

Sample Input 1 

4 10
2 3 7 8

Sample Output 1

3 7

Sample Input 2 

5 10
2 3 4 4 5

Sample Output 2

2 4 4

Sample Input 3 

2 10
5 11

Sample Output 3

-1

Hint

答案可能不唯一,本題採用special judge,輸出任意一種即可。

 

樣例1有兩種取法(2,8)(3,7),2<3,選第二種。

樣例2有兩種取法(2,3,5)(2,4,4),因為最小值都為2,兩種均滿足條件。

題意:中文題,不解釋了,表示暑假訓練最後一週沒認真做,納新題出了個輸出路徑的,一臉懵逼。。。

題解:01揹包加輸出路徑,從大往小裝可以保證最小面值最大,因為從大的開始裝,所以最後倒著輸出,可以保證升序輸出,這樣就不用排序了。 請看程式碼:

#include <iostream>
#include <algorithm>
using namespace std;
const int MAX1 = 1e4+10;
const int MAX2 = 200; //陣列都開到1e+4+10,會報錯(Runtime error)注意這裡,很坑!!!
int a[MAX1],dp[MAX2];
int vis[MAX1][MAX2];
bool cmp(int x,int y){
	return x>y;
}
int main(){
	int n,m;
	cin >> n >> m;
	for (int i = 1; i <= n;i++){
		cin >> a[i];
	}
	sort(a+1,a+n+1,cmp);
	for (int i = 1; i <= n;i++){//01揹包模板
		for (int j = m; j >= a[i];j--){
			if(dp[j]<dp[j-a[i]]+a[i]){
				vis[i][j]=1;
				dp[j]=dp[j-a[i]]+a[i];
			}
		}
	}
	if(dp[m]!=m) cout << -1 << endl;
	else{
		int i=n,f=0;
		while(m){//輸出路徑模板
			if(vis[i][m]){
				if(f==0) f=1;
				else cout << " ";
				cout << a[i];
				m-=a[i];
			}
			i--;
		}
		cout << endl;
	}
	return 0;
}