硬币组成问题
题目分析
硬币组成问题(Coin Change Problem)是经典的动态规划问题。给定不同面值的硬币和一个目标金额,要求计算出可以组成该金额的不同方式数量。
问题描述:
- 输入:硬币面值数组
coins和目标金额amount。 - 输出:组成
amount的不同组合方式数量。
示例:
- 输入:
coins = [1, 2, 5],amount = 5 - 输出:4 (组合方式:[5], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1])
思路分析
-
定义状态:
- 使用数组
dp,其中dp[i]表示组成金额i的不同组合方式数量。
- 使用数组
-
初始化:
dp[0] = 1,表示组成金额0的方式有1种,即不使用任何硬币。
-
状态转移方程:
- 对于每种硬币面值
coin,更新dp数组:
dp[j]+=dp[j−coin] dp[j] += dp[j - coin] dp[j]+=dp[j−coin] - 其中
j从coin到amount遍历。
- 对于每种硬币面值
-
结果:
- 最终
dp[amount]即为所求。
- 最终
案例解释
以 coins = [1, 2, 5] 和 amount = 5 为例,具体步骤如下:
-
初始化:
dp = [1, 0, 0, 0, 0, 0] -
使用硬币 1:
- 更新:
dp[1] = dp[1] + dp[0]→dp = [1, 1, 0, 0, 0, 0] - 更新:
dp[2] = dp[2] + dp[1]→dp = [1, 1, 1, 0, 0, 0] - 更新:
dp[3] = dp[3] + dp[2]→dp = [1, 1, 1, 1, 0, 0] - 更新:
dp[4] = dp[4] + dp[3]→dp = [1, 1, 1, 1, 1, 0] - 更新:
dp[5] = dp[5] + dp[4]→dp = [1, 1, 1, 1, 1, 1]
- 更新:
-
使用硬币 2:
- 更新:
dp[2] = dp[2] + dp[0]→dp = [1, 1, 2, 1, 1, 1] - 更新:
dp[3] = dp[3] + dp[1]→dp = [1, 1, 2, 2, 1, 1] - 更新:
dp[4] = dp[4] + dp[2]→dp = [1, 1, 2, 2, 3, 1] - 更新:
dp[5] = dp[5] + dp[3]→dp = [1, 1, 2, 2, 3, 3]
- 更新:
-
使用硬币 5:
- 更新:
dp[5] = dp[5] + dp[0]→dp = [1, 1, 2, 2, 3, 4]
- 更新:
最终,dp[5] = 4,表示组成金额5的方式有4种。
代码实现
python代码
import os
import sys
def init_arr(size):
arr = [0] * size
arr[0] = 1
return arr
def solve(coins,n,m,dp):
for i in range(n):
for j in range(coins[i],m+1):
dp[j] += dp[j-coins[i]]
n,m = map(int,input().split())
arr = list(map(int,input().split()))
dp = init_arr(m+1)
if n==0 or m==0: #这道题太坑了呀,硬币数和总额有一个是0就是0,说实话应该是1
print(0)
else:
solve(arr,n,m,dp)
print(dp[m])
C++代码
#include<bits/stdc++.h>
using namespace std;
int solve(int*,int,int,int*);
int main(){
int n,m;
cin>>n>>m;
int* coins = new int(n);
for(int i=0;i<n;i++){
cin>>coins[i];
}
int* dp = new int(m+1);
fill(dp,dp+m+1,0);
dp[0] = 1;
int res = solve(coins,n,m,dp);
cout<<res;
return 0;
}
int solve(int* coins,int n,int m,int* dp){
for(int i=0;i<n;i++){
for(int j=*(coins+i);j<=m;j++){
*(dp+j) += *(dp+j-*(coins+i));
}
}
print_arr(dp,m+1);
if (n==0 or m==0){
return 0;
}
else{
return *(dp+m);
}
}
总结
硬币组成问题是一个典型的动态规划问题,关键在于定义状态、初始化和状态转移。通过对不同硬币的使用情况进行遍历,可以有效地计算出组成目标金额的不同方式。


被折叠的 条评论
为什么被折叠?



