考研复试上机题-最小邮票数
题目描述
有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。 如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。
输入描述:
有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。
输出描述:
对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。
示例1
输入
10
5
1 3 3 3 4
输出
3
解题思路
本题为典型的dfs题,数据量不大,可以直接用深度搜索解决,当然在进行搜索的过程中要注意剪枝和更新构成邮票的数量。
一、遇到以下情况我们停止搜索:
1、当邮票总值s>n的时。
2、当s == n 的时候,我们把邮票数number 更新成 min(number,num),然后停止搜索。
3、当选到最后一张邮票时,停止搜索;
4、当当前所选的邮票数大于以及能够组合成n面值的邮票数数量时,停止搜索。
二、dfs以后,我们对number进行判断,为-1时输出0,否则输出我们的dfs值。
解题代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include<vector>
#define rep(i,s,e) for(int i = s;i<e;i++)
using namespace std;
const int maxn = 200;
struct Sovle{
int num;
int sumNumber = -1;
int sum;
int a[maxn];
vector<int>token;
void init(int n,int s){
num = n;
sum = s;
}
void addToken(int n){
token.push_back(n);
a[token.size()-1] = n;
}
int dfs(int x,int s,int number){
if(s==sum){
if(sumNumber==-1){
sumNumber = number;
}else{
sumNumber = min(sumNumber,number);
}
}
if(x>=num){
return 0;
}
rep(i,x,num){
s += a[i];
number++;
if(s<=sum){
dfs(i+1,s,number);
}
number--;
s-=a[i];
}
return 0;
}
int getDfs(){
dfs(0,0,0);
return sumNumber;
}
};
int main()
{
int n;
while(cin>>n){
int num;
cin>>num;
Sovle so;
so.init(num,n);
rep(i,0,num){
int t;
cin>>t;
so.addToken(t);
}
int t = so.getDfs();
if(t!=-1)
cout<<t<<endl;
else cout<<0<<endl;
}
}