先挂上题目链接~https://www.patest.cn/contests/pat-a-practise/1068
分析:给定多少钱,问能不能通过已有的硬币组合凑成该整数,如果可以,输出硬币字典序最小的组合;否则输出”No Solution“。此类组合问题我们当然是想到万能的搜索~推荐dfs,个人用的比较习惯。注意事项如下:
1、找字典序最小的一种思路是将硬币按面值大小升序排序,这样我们dfs搜出的第一种情况便是答案(可以仔细想想为什么
2、如果就按上面的思路进行深搜会有几个测试点超时TAT,剪枝则是求出第一种情况后,后续搜索直接返回(通过设置标志位判断)。然而,即使是这样在最后一个测试点还是会超时,一个原因是数据量比较大,很皮的是这个情况根本没有solution,于是特判就好啦。求出所有硬币的面值总和sum,如果sum<m,则直接输出”No Solution“,于是问题就这样解决了~
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4+10;
int coin[maxn];
int n,m;
bool vis[maxn]={false};
bool flag = false,first=true;
vector<int> ansPath;
int k;
void dfs(int cur, vector<int> path, int w){
if(flag) return;
vis[cur] = true;
if(w > m) return;
if(w == m){
flag = true;
if(first){
ansPath = path;
first = false;
}
return;
}
for(int i = 1; i<=k; i++){
if(!vis[i]){
path.push_back(coin[i]);
dfs(i, path, w+coin[i]);
vis[i] = false;
path.pop_back();
}
}
}
int main(){
scanf("%d%d", &n, &m);
long sum = 0;
for(int i = 1; i<=n; i++){
scanf("%d", &coin[i]);
sum += coin[i];
}
if(sum < m) printf("No Solution");
else {
sort(coin+1, coin+n+1);
k = n;
for(int i = 1; i<=n; i++)
if(coin[i]>=m){
k = i;
break;
}
dfs(0, ansPath, 0);
if(flag){
printf("%d", ansPath[0]);
for(int i = 1; i<ansPath.size(); i++)
printf(" %d", ansPath[i]);
}
else printf("No Solution");
}
return 0;
}