动态规划之找零问题

1、什仫是动态规划问题?

动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,并将这些子问题的解保存起来,如果以后在求解较大子问题的时候需要用到这些子问题的解,就可以直接取出这些已经计算过的解而免去重复运算。保存子问题的解可以使用填表方式,例如保存在数组中。

2、下面来看一个动态规划的例子–找零问题

给予不同面值的硬币若干(每种硬币个数无限多),如何用若干种硬币组合为某种面额的钱,使硬币的的个数最少?

在实际生活中,我们往往使用的是贪心算法,比如找零钱时候需要13元,是10+2+1。但是假若硬币的面值是1,2,5,所要找的零钱total=9,是不是贪心算法就无法解决了呢?在这里就用到动态规划的思想了。
下来来分析一个具体的例子,假设面值为1,2,5,21,25,需要找零total=63,那仫只需要找到3个21即可。那仫如何体现出由子问题解决大问题的动态规划思想呢?

money[]--=>保存硬币面值的数组
len-->硬币面值不同的硬币种类数量,也就是money数组的大小
total-->需要找零的钱币
coinMoney[]-->保存找零为i的所需要的最小的硬币数

当计算找零为i的最少硬币数coinMoney[i]的时候,可以将该问题分解为求coinMoney[i-value]和一个面值为value元的硬币,因为i-cents<i,所以coinMoney[i-value]必然存在,如果币值为value的硬币满足题意,那仫最终解coinMoney[i]=coinMoney[i-value]+1,也就是面值为value的这一个硬币。
3、代码实现

//动态规划之找零问题
void MakeMoney(int *money, int len, int total)
{
    int *coinMoney = new int[total + 1];   //下标为0的位置不用
    coinMoney[0] = 0;
    int i = 1;
    //i-->钱币面值,money[i]表示找零的最小硬币数
    for (; i <= total; i++)    //i控制1~total之间的每种币值都找零钱,也就是若干子问题
    {
        int minMoney = i;
        for (int j = 0; j < len; j++)   //j是控制每种钱币面值是否在找零钱的范围内
        {
            if (i >= money[j])   //要找的零钱i大于硬币的面值
            {
                int tmp = coinMoney[i - money[j]] + 1;
                if (tmp < minMoney)   //更新所需要的最少的硬币数
                {
                    minMoney = tmp;
                }
            }
        }
        coinMoney[i] = minMoney;
    }
    printf("找零为%d需要的最小硬币数为%d\n", total, coinMoney[i-1]);
    delete[]coinMoney;
}

int main()
{
    int money[] = { 1, 2, 5, 21, 25 };
    int len = sizeof(money) / sizeof(money[0]);
    int total = 63;
    MakeMoney(money, len, total);
    system("pause");
    return 0;
}

如果有理解的不正确的地方,欢迎指出。

    原文作者:动态规划
    原文地址: https://blog.csdn.net/ONEDAY_789/article/details/78448425
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞