------> 原题链接 <-------
题意大概是有1w个硬币,店家只要精确数额(不多收也不找零)问能否凑出给出的数额。
做法就是暴力循环 + 剪枝优化
不剪枝的话有一个点是过不去的。
1、剔除所有大于给定数量的硬币,
2、对于重复的硬币,如果第一个不行,那么排除掉后面所有的重复硬币的可能性。(见注释的核心剪枝行)
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
int amount;
int n;
int coins[10000];
using namespace std;
vector<int> path;
int compare_ints(const void* a, const void* b) // comparison function
{
int arg1 = *reinterpret_cast<const int*>(a);
int arg2 = *reinterpret_cast<const int*>(b);
if(arg1 < arg2) return -1;
if(arg1 > arg2) return 1;
return 0;
}
bool find(int start, int target){
for (int i = start; i < n; i++)
{
if(coins[i] > target){
return false;
}
if(coins[i] == target) {
path.push_back(i);
return true;
}
if(coins[i] < target){
path.push_back(i);
if(find(i + 1, target - coins[i])) return true;
else path.pop_back();
while(i < n && coins[i] == coins[i+1]) i++; //这一句是核心的剪枝,如果没有这一行最后一个case就会超时。
}
}
return false;
}
int main(){
int tmp;
int cnt = 0;
scanf ("%d %d", &n, &amount);
for (int i = 0; i < n; i++) {
scanf ("%d", &tmp);
if(tmp <= amount) coins[cnt++] = tmp;
}
n = cnt;
qsort(coins, n, sizeof(int), compare_ints);
if(find(0, amount)){
printf("%d",coins[path[0]]);
for (int i = 1; i < path.size(); i++)
{
printf(" %d", coins[path[i]]);
}
}
else printf("No Solution\n");
}