PAT1068 Find More Coins (30)(DP)

题意:

给出n枚钱币,要求买价值为m的物品,要求输出具体所用的钱币,如有多种情况输出字典序最小的情况。

思路:

这题就是01背包的变种,状态转移方程很好写:dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+c[i])

主要难点在于怎么处理多种情况最后输出,基本思路是一开始将钱币按从大到小排序,在状态转移的过程中用hash[i][j]保存是否选取了当前钱币i,这样最后对dp[n][m]倒序输出时会优先输出币值小的从而符合字典序。

#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
const int maxn = 10050;
int num[maxn], dp[maxn][150];
int pos[maxn][150];

int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		scanf("%d", &num[i]);
	sort(num+1, num + n+1, greater<int>());
	for (int i = 1; i <= n; i++) {
		for (int j = num[i]; j <= m; j++) {
			if (dp[i - 1][j] <= dp[i-1][j - num[i]] + num[i]) {
				dp[i][j] = dp[i-1][j - num[i]] + num[i];
				pos[i][j] = 1;
			} else {
				dp[i][j] = dp[i - 1][j];
				pos[i][j] = 0;
			}
		}
	}	
	if (dp[n][m] != m)
		printf("No Solution\n");
	else {
		vector<int> res;
		int road = m,index=n;
		while (road > 0) {
			if (pos[index][road]==1) {
				res.push_back(num[index]);
				road -= num[index];
			}
			index--;
		}
		for (int i = 0; i<res.size(); i++) {
			if (i == 0)
				printf("%d", res[i]);
			else
				printf(" %d", res[i]);
		}
	}	
	return 0;
}

posted @ 2018-05-31 14:42  seasonal  阅读(61)  评论(0编辑  收藏  举报