解题报告-L3-001-凑零钱
韩梅梅喜欢满宇宙到处逛街。现在她逛到了一家火星店里,发现这家店有个特别的规矩:你可以用任何星球的硬币付钱,但是绝不找零,当然也不能欠债。韩梅梅手边有 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
解题思路
- 按照要求的最小序列,可以知道硬币的面值需要排序,而且按照DFS搜索的顺序肯定能找到最小序列。
- n的数量明显大过m,为了时间短,肯定只取前面的10^2个value
- 一开始没有充分利用value已经排序好的特性来剪枝,导致还是需要深入空搜很多层:后面进行了改进。
- “全部加起来还不够”:反正又不难写,判断一下呗~实际上最后一个TLE就是因为这个。
代码
一开始,最后一个case TLE
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdio>
#include <bitset>
using namespace std;
static int n, m;
static int curr;
static int* value;
static bool* isUsed;
bool dfs(int in){ // before index in
if(in == n) return curr == m;
if(curr + value[in] == m){ // succeed
isUsed[in] = true;
return true;
}
else{
if(curr + value[in] < m){
isUsed[in] = true;
curr += value[in];
bool ok = dfs(in + 1);
if(ok) return true;
else{
isUsed[in] = false;
curr -= value[in];
}
}
return dfs(in + 1);
}
}
int main(){
cin >> n >> m;
curr = 0;
value = new int[n];
isUsed = new bool[n];
for(int i=0; i<n; i++){
scanf("%d", &value[i]);
isUsed[i] = false;
}
sort(value, value+n);
if(n > 100) n = 100;
bool ok = dfs(0);
if(ok){
bool flag = true;
for(int i=0; i<n; i++){
if(isUsed[i]){
if(flag) flag = false;
else printf(" ");
printf("%d", value[i]);
}
}
}
else cout << "No Solution";
return 0;
}
AC代码
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdio>
#include <bitset>
using namespace std;
static int n, m;
static int curr;
static int* value;
static bool* isUsed;
bool dfs(int in){ // before index in
// curr will forever < m
if(in == n) return curr == m;
if(curr + value[in] == m){ // succeed
isUsed[in] = true;
return true;
}
else if(curr + value[in] > m) return false;
else{
isUsed[in] = true;
curr += value[in];
bool ok = dfs(in + 1);
if(ok) return true;
else{ // isUsed[in] = false
isUsed[in] = false;
curr -= value[in];
return dfs(in + 1);
}
}
}
int main(){
cin >> n >> m;
curr = 0;
value = new int[n];
isUsed = new bool[n];
for(int i=0; i<n; i++){
scanf("%d", &value[i]);
isUsed[i] = false;
}
sort(value, value+n);
if(n > 100) n = 100;
// sum of value < m?
int tmp = 0;
for(int i=0; i<n; i++)
tmp += value[i];
if(tmp < m){
cout << "No Solution";
return 0;
}
// judge and output
if(dfs(0)){
bool flag = true;
for(int i=0; i<n; i++){
if(isUsed[i]){
if(flag) flag = false;
else printf(" ");
printf("%d", value[i]);
}
}
}
else cout << "No Solution";
return 0;
}