0
点赞
收藏
分享

微信扫一扫

硬币面值组合(上台阶)

沪钢木子 2022-12-02 阅读 197


 假设我们有8种不同面值的硬币{1,2,5,10,20,50,100,200},用这些硬币组合够成一个给定的数值n。问总过有多少种可能的组合方式? 类似的题目还有:

  [华为面试题] 1分2分5分的硬币三种,组合成1角,共有多少种组合

  [创新工厂笔试题] 有1分,2分,5分,10分四种硬币,每种硬币数量无限,给定n分钱,有多少中组合可以组成n分钱

  • 一个人上台阶可以一次上1个,2个,或者3个,问这个人上n层的台阶,总共有几种走法? 
    问法不一样,但是本质一样!


1.方法一


深度搜索解答树



#include<iostream>
#include<vector>
using namespace std;

int coin[4] = { 1, 2, 5, 10 };
vector<int> solution;
int cnt = 0;
int sum = 0;

int target = 0;

void dfs(int index){
if (sum == target){
cnt++;

for (int i = 0; i<solution.size(); i++){
cout << solution[i];
}
cout << endl;
return;
}
if (sum > target){
return;
}

for (int i = index; i < 4; i++){// index,否则有重复
sum += coin[i];
solution.push_back(coin[i]);
dfs(i);
solution.pop_back();
sum -= coin[i];
}

}

int main(){

cnt = 0;
sum = 0;

target = 5;

dfs(0);

cout << "cnt=" << cnt << endl;

return 0;
}

结果为4


2.方法二-动态规划


给定一个数值sum,假设我们有m种不同类型的硬币{V1, V2, ..., Vm},如果要组合成sum,那么我们有

sum = x1 * V1 + x2 * V2 + ... + xm * Vm 

求所有可能的组合数,就是求满足前面等值的系数{x1, x2, ..., xm}的所有可能个数。

dp[i][sum] = 用前i种硬币构成sum 的所有组合数。

  那么题目的问题实际上就是求dp[m][sum],即用前m种硬币(所有硬币)构成sum的所有组合数。

dp[i][sum] = dp[i-1][sum - 0*Vm] + dp[i-1][sum - 1*Vm]

+ dp[i-1][sum - 2*Vm] + ... + dp[i-1][sum - K*Vm]; 其中K = sum / Vm

那么初始情况是什么呢?如果sum=0,那么无论有前多少种来组合0,只有一种可能,就是各个系数都等于0;

dp[i][0] = 1   // i = 0, 1, 2, ... , m

我们规定为dp[0][sum] = 0. 

#include<iostream>
#include<vector>
using namespace std;


int coinCombination(int coin[], int coinKinds, int target){
vector<vector<int> >dp(coinKinds + 1, vector<int>(target + 1));

for (int i = 0; i <= coinKinds; i++){
dp[i][0] = 1;
}

dp[0][target] = 0;

for (int i = 1; i <= coinKinds; i++){
for (int j = 1; j <= target; j++){
dp[i][j] = 0;
for (int k = 0; k <= j / coin[i - 1]; k++){//<=
dp[i][j] += dp[i - 1][j - k*coin[i - 1]];//+=
}
}
}

return dp[coinKinds][target];
}


int main(){

int coin[4] = { 1, 2, 5, 10 };

cout << coinCombination(coin, 4, 5) << endl;

return 0;
}



举报

相关推荐

0 条评论