零钱有限制和没有限制的找零钱问题

在参加腾讯模拟考的时候,其中的一道编程题是找零钱的问题,但是零钱的数量是一定的,并不是无限的。而且零钱都是2的K次幂,1,2,4,8,16,….每种零钱的数量是 2,给定一个数 n (

int k_count = 0;
    long long  k_sum = 1;

    while (k_sum < n)           //小于且最接近n的2的K次幂的整数
    {
        k_sum = k_sum * 2;
        k_count++;
    }

    vector<long long > arr(k_count, 0);   //把相应的零钱存入数组中
    k_sum = 1;
    arr[0] = 1;
    for (int i = 1; i < k_count; ++i)
    {
        k_sum *= 2;
        arr[i] = k_sum;
    }

要枚举的动态规划的方法

vector<long long> temp(n+1, 0);
    vector<vector<long long>>  dp(k_count, temp);


    for (int i = 0; i < k_count; ++i)
        dp[i][0] = 1;
    dp[0][1] = 1;        //因为每种零钱的数量只有两张
    dp[0][2] = 1;


    for (int i = 1; i < k_count; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            if (j < arr[i])                  //如果总的钱数,小于当前的零钱
                dp[i][j] = dp[i - 1][j];
            else
            {
                int count = 0;
                for (int k = 0; arr[i] * k <= j && k < 3; ++k)     //计算用 k 张arr[i] 的零钱的时候,用多少张找零的方式
                    count += dp[i - 1][j-arr[i]*k];
                dp[i][j] = count;
            }

        }
    }

后来采用优化的动态规划,发现结果不对


    for (int i = 1; i < k_count; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            if (j < arr[i])                  //如果总的钱数,小于当前的零钱
                dp[i][j] = dp[i - 1][j];
            else
            {               
                dp[i][j] = dp[i - 1][j] + dp[i][j-arr[i]];      //在每张零钱的张数限制的条件下时不能采用这种优化的方法
            }

        }
    }

后来发现问题是,因为零钱的数量是限制的,所以不能采用这种优化的方法,只能通过枚举来实现动态规划,dp[i][j] = dp[i - 1][j] + dp[i][j-arr[i]]; 这个表达式中已经用了一次 arr[i],而你在用 dp[i][j-arr[i]]时,这个方法中也会用掉 arr[i],所以就会造成结果出错的情况,如果有无限的零钱的话,那就可以采用优化过的动态规划算法。

猜你喜欢

转载自blog.csdn.net/u014077947/article/details/79679279
今日推荐