PTA L3-001 凑零钱 (01背包/DFS)

                                               L3-001 凑零钱 (30 分)

韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 10​4​​ 枚来自各个星球的硬币,需要请你帮她盘算一下,是否可能精确凑出要付的款额。

输入格式:

输入第一行给出两个正整数:N(≤10​4​​)是硬币的总个数,M(≤10​2​​)是韩梅梅要付的款额。第二行给出 N 枚硬币的正整数面值。数字间以空格分隔。

输出格式:

在一行中输出硬币的面值 V​1​​≤V​2​​≤⋯≤V​k​​,满足条件 V​1​​+V​2​​+...+V​k​​=M。数字间以 1 个空格分隔,行首尾不得有多余空格。若解不唯一,则输出最小序列。若无解,则输出 No Solution

注:我们说序列{ A[1],A[2],⋯ }比{ B[1],B[2],⋯ }“小”,是指存在 k≥1 使得 A[i]=B[i] 对所有 i

输入样例 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背包

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
static const ll Mod = 1e9 + 7;
static const int MAX_N = 1e4 + 5;
int w[MAX_N];
int dp[1005];
bool vis[MAX_N][1005];
int main() {
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	int n, weight;
	while (scanf("%d%d", &n, &weight) != EOF) {
		memset(vis, false, sizeof(vis));
		memset(dp, 0, sizeof(dp));
		for (int i = 0; i < n; ++i) scanf("%d", &w[i]);
		sort(w, w + n, greater());//从大到小排序,填表完成即可找到最小序列
		for (int i = 0; i < n; ++i) {
			for (int j = weight; j >= w[i]; --j) {
				if (dp[j - w[i]] + w[i] >= dp[j]) {
					dp[j] = dp[j - w[i]] + w[i];
					vis[i][j] = true;
				}
			}
		}
		if (dp[weight] != weight) printf("No Solution\n");
		else {
			vectorvec;
			int max_v = weight, ind = n - 1;
			while (max_v) {
				if (vis[ind][max_v]) {
					max_v -= w[ind];
					vec.push_back(w[ind]);
				}
				--ind;
			}
			for (int i = 0; i < vec.size() - 1; ++i) printf("%d ", vec[i]);
			printf("%d\n", vec[vec.size() - 1]);
		}
	}
	return 0;
}

DFS,需要剪枝一下,不然有些测试点会超时

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
static const ll Mod = 1e9 + 7;
static const int MAX_N = 1e4 + 5;
int w[MAX_N];
bool vis[MAX_N];
void dfs(int s, int cur_v, int n, int weight, bool &flag) {
	if (flag) return;
	else if (cur_v > weight) return;
	else if (cur_v == weight) {
		flag = true;
		int ind = 0;
		vectorvec;
		while (cur_v) {
			if (vis[ind]) {
				vec.push_back(w[ind]);
				cur_v -= w[ind];
			}
			++ind;
		}
		for (int i = 0; i < vec.size() - 1; ++i) printf("%d ", vec[i]);
		printf("%d\n", vec[vec.size() - 1]);
		return;
	}
	else if (s == n) return;
	else {
		vis[s] = true;
		dfs(s + 1, cur_v + w[s], n, weight, flag);
		vis[s] = false;
		if (flag) return;
		dfs(s + 1, cur_v, n, weight, flag);
	}
}
int main() {
	/*freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);*/
	int n, weight;
	while (scanf("%d%d", &n, &weight) != EOF) {
		memset(vis, false, sizeof(vis));
		int sum_v = 0;
		for (int i = 0; i < n; ++i) {
			scanf("%d", &w[i]);
			sum_v += w[i];
		}
		if (sum_v < weight) { printf("No Solution\n"); continue; }	//没有这个剪枝最后一个测试点会超时
		sort(w, w + n);    //从小到大排序,搜索到weight便是最小序列
		bool flag = false;
		dfs(0, 0, n, weight, flag);
		if (!flag) printf("No Solution\n");
	}
	return 0;
}

 

你可能感兴趣的:(动态规划)