L3-001 凑零钱 (30 分)
韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 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背包
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#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<int>());//从大到小排序,填表完成即可找到最小序列
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 {
vector<int>vec;
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 <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#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;
vector<int>vec;
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;
}