动态规划(DP)---- 硬币问题(3)

今天是24年的第一天,博主在这里祝大家元旦快乐,风驰电掣,如龙腾空。

在上一篇的文章,我们讲到了如何选出硬币全部组合数,这期给大家带来的是最后一期的硬币问题,限制硬币的数量我们应该怎么办?

在开始前,我们先回顾一下上期讲述的硬币组合数的状态方程,如下.....

dp[j] = dp[j] + dp[j - w[i]];

这里的dp[j]数组的含义代表j金额所对应的硬币组合数,那么我们在这道题的基础上进行分析,限制应该怎么办?

我们可以这样想,在我们前面的硬币问题是所加和的硬币金额作为限制条件,其就是j,那么我们可以建立二维数组来存放硬币的数量。也就是设dp[j][num],其中j代表金额,num代表硬币数量,dp数组代表用i个硬币可以组成金额j的方案数量,也就是建立一个“转移矩阵”。那么我们上面的状态转移方程来变形一下就可以得到....

dp[j][num] = dp[j][num] + dp[j - w[i]][num - 1];

在这里我们可以仿照硬币问题(2)中状态转移方程的推导进行分析,也就是自己本身的方案数+每一种硬币的方案数,如果选择一个硬币加入的话其总硬币数就要减去一个。那么见代码....

#include
const int N = 1000;
int w[N];
int dp[N][N];
int money;
int coin;
int arr[N];
void solve()
{
	dp[0][0] = 1;//初始化
	for(int i = 0;i < 5;i++)//枚举硬币
	{
		for(int j = w[i];j <= money;j++)//遍历总金额
		{
			for(int num = 0;num <= coin;num++)//枚举硬币数量
			{
				dp[j][num] = dp[j][num] + dp[j - w[i]][num - 1];//状态转移方程
			}
		}
	}
}
int main()
{
	scanf("%d %d",&money,&coin);
	for(int i = 0;i < 5;i++)
	{
		scanf("%d",&w[i]);
	}
	solve();
	for(int i = 0;i <= money;i++)
	{
		for(int j = 0;j <= coin;j++)
		{
			arr[i] += dp[i][j];//将coin限制的硬币的组合数加和
		}
	}
	printf("%d",arr[money]);
	return 0;
}

这里小编要强调一下哦,那个三重for循环的遍历顺序如何思考,我们可以想象成一个一维数组作为行,也就是数学换元的思想将其整体变成了行,而coin作为列,然后就是二维数组的演示图了。当然,这样想比较好理解,网友要是有别的想法也是可以的,这里我个人是这样理解觉得比较好,也欢迎大佬吧这里的遍历想法扣在评论区内。

好了本期视频分享到这里了,感谢收看,祝福各位在龙年有新的收获啦,我们下期再见。

你可能感兴趣的:(动态规划,算法)