【问题标题】:Coin Change Algorithm C硬币找零算法 C
【发布时间】:2018-03-21 01:51:12
【问题描述】:

我在为以下问题想出一个可行的算法时遇到了一些麻烦。

给定 100、50、25 和 10 美分的可用硬币数量,我需要找到如何将这些硬币组合成给定值 x。 (不一定是最优的,可用硬币的任何组合都可以)。

到目前为止,我已经得到了这段代码,它只适用于某些情况。

struct coins{
    int valor;
    int quant;
};

int change = 0;
int changecoins[4] = {0};
struct coins available_coins[4] = { 0 };

moedas_disp[3].value = 10; //10 cents coins
moedas_disp[2].value = 25; //25 cents coins
moedas_disp[1].value = 50;  //50 cents coins
moedas_disp[0].value = 100; //100 cents coins

//quantity values just for test purposes
moedas_disp[3].quant = 10; //10 cents coins
moedas_disp[2].quant = 15; //25 cents coins
moedas_disp[1].quant = 8;  //50 cents coins
moedas_disp[0].quant = 12; //100 cents coins


for(int i=0; i<4; i++){
    while((change/available_coins[i].value>0)&&(available_coins[i].quant>0)){
        change -= available_coins[i].value;
        available_coins[i].quant--;
        changecoins[i]++;
    }
}
if(change>0){
    printf("It was not possible to change the value");
}
else{
    printf("Change:\n");
    printf("\t%d 100 cent coin(s).\n", changecoins[0]);
    printf("\t%d 50 cent coin(s).\n", changecoins[1]);
    printf("\t%d 25 cent coin(s).\n", changecoins[2]);
    printf("\t%d 10 cent coin(s).\n", changecoins[3]);
}

但是对于像 30 这样的数量,这将不起作用。该程序将适合 1 个 25 美分的硬币,但剩下 5 美分,这将无法计算。 40、65 等也会出现这种情况。

提前致谢!

【问题讨论】:

  • 使用调试器单步调试代码,看看它在哪里没有按您的预期工作。
  • 听起来你可能需要学习如何使用调试器来单步调试你的代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。延伸阅读:How to debug small programs
  • 我认为不是某些行特别是错误的,而是算法逻辑。而且我想不出一个适用于 100% 案例的逻辑。 (我已经尝试了很长时间)
  • 正如我们所说,使用调试器单步调试代码,看看它在哪里没有按您的预期工作。调试器为您工作,就像它为我们工作一样,这是一个极好的学习机会。学习使用调试器永远不会太早,调试器是开发人员工具箱中最强大的工具之一。就逻辑而言,抓起一张纸和铅笔并完成它。你是怎么做到的?
  • 解决问题的好方法还可以处理无法更改输入值的情况(例如 15 美分)。此外,请注意任何可以使用 100 美分硬币或 50 美分硬币制作的价值都可以使用 10 美分硬币制作。因此,考虑只用 10 美分硬币和 25 美分硬币找零的更简单情况会有所帮助。优化可以稍后进行。

标签: c algorithm coin-change


【解决方案1】:

您可以按照以下步骤使用递归算法:

  • 拿 1 100c 硬币,尝试将剩余的数量分解为 50、25、10s
  • 如果这不起作用,请取 2 100c 硬币并尝试将剩余的金额分解为仅 50、25、10s

如果您尝试了 100c 硬币数量的所有可能性(包括 0 个!),那么您将涵盖所有可能的解决方案。

我写了一些演示代码。如果这是家庭作业,那么请不要复制粘贴我的代码,但是一旦您了解所涉及的想法,就可以编写自己的代码...

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

bool coin_find(unsigned int total, unsigned int *denom)
{
    if ( total == 0 )
        return true;    // Success - reduced total remaining to 0

    if ( *denom == 0 )
        return false;   // Failure - tried all coins in the list with no solution yet

    // Try 0 of the largest coin, then 1, etc.
    for (unsigned int d = 0; ; ++d)
    {
        if ( d * *denom > total )
            return false;

        if ( coin_find(total - d * *denom, denom + 1) )
        {
            if ( d ) 
                printf("%ux%uc ", d, *denom);
            return true;
        }
    }
}

int main(int argc, char **argv)
{
    if ( argc < 2 )
        return EXIT_FAILURE;

    unsigned int denoms[] = { 100, 50, 25, 10, 0 };

    long t = strtol(argv[1], NULL, 10);
    if ( t < 0 || t >= LONG_MAX )
        return EXIT_FAILURE;

    if ( !coin_find(t, denoms) )
        printf("No solution found");

    printf("\n");
}

读者练习:

  1. 向后循环而不是向前循环,以便我们在默认情况下找到更整洁的解决方案。
  2. 仅输出硬币数量最少的细分。
  3. 输出所有可能的故障。

奖励练习:

  • 将其重写为根本不使用递归;而是使用一个包含迄今为止解决方案的数组,并在您到达终点时回溯。这样练习 3 实际上会更容易。

【讨论】:

  • 非常感谢!这对我帮助很大:)
【解决方案2】:

以下解决方案使用动态规划,只要M(为您提供x)的值很小,您就可以使用它。如果prev[j]-1 不同,则这意味着j 可以用给定的硬币制作。 coin[j]存储用于制作j的硬币的价值,prev[j]是不使用coin[j]的价值。因此,(j - prev[j]) / coin[j] 给了我们用于制造重量的coin[j] 面额硬币的数量j

#include <stdio.h>

const int
    COINS = 4;

int M = 1100; 
int prev[10000];
int coin[10000];
// Available denominations.
int value[COINS] = { 10, 25, 50, 100 };
// Available quantities.
int quant[COINS] = { 10, 15, 8, 12 };
// Number of selected coins per denomination.
int answer[COINS] = { 0, 0, 0, 0 };

int main() {
    // base case    
    prev[0] = 0;
    for (int i = 1; i < 10000; i++)
        prev[i] = -1;

    // dynamic programming
    for (int i = 0; i < COINS; i++)
        for (int j = M; j >= 0; j--)
            if (prev[j] != -1) {
                int k = 1;
                while (k <= quant[i] && j + k * value[i] <= M) {
                    if (prev[j + k * value[i]] == -1) {
                        prev[j + k * value[i]] = j;
                        coin[j + k * value[i]] = value[i];
                    }
                    k++;
                }
            }

    // build the answer
    if (prev[M] != -1) {
        int current = M;
        while (current > 0) {
            int k = 0;
            while (k < COINS && coin[current] != value[k])
                k++;
            answer[k] += (current - prev[current]) / coin[current];
            current = prev[current];
        }
        printf("Change\n");
        for (int i = 0; i < COINS; i++)
            printf("\t%d %d cent coin(s).\n", answer[i], value[i]);
    } else {
        printf("It was not possible to change the value");
    }

    return 0;
}

【讨论】:

    【解决方案3】:

    因为25%10不等于0,所以需要考虑。试试这个算法:

    #include <stdio.h>
    
    struct coins{
        int value;
        int quant;
    };
    
    int main()
    {
        int change = 30;
        int changecoins[4] = {0};
        struct coins available_coins[4] = { 0 };
        int temp;
    
        available_coins[3].value = 10; //10 cents coins
        available_coins[2].value = 25; //25 cents coins
        available_coins[1].value = 50;  //50 cents coins
        available_coins[0].value = 100; //100 cents coins
    
        //quantity values just for test purposes
        available_coins[3].quant = 10; //10 cents coins
        available_coins[2].quant = 15; //25 cents coins
        available_coins[1].quant = 8;  //50 cents coins
        available_coins[0].quant = 12; //100 cents coins
    
    
        if(((change/10 < 2)&&(change%10 != 0)) || (change/10 >= 2)&&((change%10 != 5) && change%10 != 0)) {
            printf("It was not possible to change the value\n");
            return 0;
        }
        else {
            for(int i=0; i<2; i++){
                changecoins[i] = change / available_coins[i].value;
                change = change % available_coins[i].value;
                if(changecoins[i] >= available_coins[i].quant) {
                    change = change + (changecoins[i] - available_coins[i].quant) * available_coins[i].value;
                    changecoins[i] = available_coins[i].quant;
                }
            }
    
            if(change%10 == 5) {
                if(available_coins[2].quant < 1) {
                    printf("It was not possible to change the value\n");
                    return 0;
                }
                else {
                    changecoins[2] = change / available_coins[2].value;
                    change = change % available_coins[2].value;
                    if(changecoins[2] >= available_coins[2].quant) {
                        change = change + (changecoins[2] - available_coins[2].quant) * available_coins[2].value;
                        changecoins[2] = available_coins[2].quant;
                    }
                    if(change%10 == 5) {
                        changecoins[2]--;
                        change = change + available_coins[2].value;
                    }
                }
            }
    
            changecoins[3] = change / available_coins[3].value;
            change = change % available_coins[3].value;
            if(changecoins[3] >= available_coins[3].quant) {
                change = change + (changecoins[3] - available_coins[3].quant) * available_coins[3].value;
                changecoins[3] = available_coins[3].quant;
            }
    
            if(change>0) {
                printf("It was not possible to change the value\n");
            }
            else {
                printf("Change:\n");
                printf("\t%d 100 cent coin(s).\n", changecoins[0]);
                printf("\t%d 50 cent coin(s).\n", changecoins[1]);
                printf("\t%d 25 cent coin(s).\n", changecoins[2]);
                printf("\t%d 10 cent coin(s).\n", changecoins[3]);
    
                for(int i = 0; i < 4; i++) {
                    available_coins[i].quant -= changecoins[i];
                }
            }
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 1970-01-01
      • 2023-03-02
      相关资源
      最近更新 更多