确定硬币组合的算法

发布于 2024-11-05 03:05:40 字数 324 浏览 5 评论 0原文

最近,我遇到了一个关于编程算法的提示,但我不知道该怎么做。我以前从未真正编写过算法,所以我在这方面还是个新手。

该问题要求编写一个程序来确定收银员根据硬币价值和硬币数量找零的所有可能的硬币组合。例如,一种货币可能有 4 个硬币:2 分、6 分、10 分和 15 分硬币。等于 50 美分的组合有多少种?

我使用的语言是 C++,尽管这并不重要。

编辑:这是一个更具体的编程问题,但是我如何分析 C++ 中的字符串来获取硬币值?它们在文本文档中给出

4 2 6 10 15 50 

(其中本例中的数字对应于我给出的示例)

I was recently faced with a prompt for a programming algorithm that I had no idea what to do for. I've never really written an algorithm before, so I'm kind of a newb at this.

The problem said to write a program to determine all of the possible coin combinations for a cashier to give back as change based on coin values and number of coins. For example, there could be a currency with 4 coins: a 2 cent, 6 cent, 10 cent and 15 cent coins. How many combinations of this that equal 50 cents are there?

The language I'm using is C++, although that doesn't really matter too much.

edit: This is a more specific programming question, but how would I analyze a string in C++ to get the coin values? They were given in a text document like

4 2 6 10 15 50 

(where the numbers in this case correspond to the example I gave)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

念﹏祤嫣 2024-11-12 03:05:40

这个问题被称为硬币找零问题。请检查 了解详细信息。此外,如果您搜索“硬币找零”或“动态编程硬币找零”,那么您将获得许多其他有用的资源。

This problem is well known as coin change problem. Please check this and this for details. Also if you Google "coin change" or "dynamic programming coin change" then you will get many other useful resources.

为人所爱 2024-11-12 03:05:40

下面是 Java 中的递归解决方案:

// Usage: int[] denoms = new int[] { 1, 2, 5, 10, 20, 50, 100, 200 };       
// System.out.println(ways(denoms, denoms.length, 200));
public static int ways(int denoms[], int index, int capacity) {
    if (capacity == 0) return 1;
    if (capacity < 0 || index <= 0 ) return 0;
    int withoutItem = ways(denoms, index - 1, capacity); 
    int withItem = ways(denoms, index, capacity - denoms[index - 1]); 
    return withoutItem + withItem;
}

Here's a recursive solution in Java:

// Usage: int[] denoms = new int[] { 1, 2, 5, 10, 20, 50, 100, 200 };       
// System.out.println(ways(denoms, denoms.length, 200));
public static int ways(int denoms[], int index, int capacity) {
    if (capacity == 0) return 1;
    if (capacity < 0 || index <= 0 ) return 0;
    int withoutItem = ways(denoms, index - 1, capacity); 
    int withItem = ways(denoms, index, capacity - denoms[index - 1]); 
    return withoutItem + withItem;
}
暗地喜欢 2024-11-12 03:05:40

这看起来有点像分区,只不过您没有使用 1:50 中的所有整数。它看起来也类似于装箱问题,但略有不同:

其实想了想,就是ILP,因此是 NP 困难的。

我建议一些动态编程方法。基本上,您可以定义一个值“余数”并将其设置为您的目标(例如 50)。然后,在每一步中,您都需要执行以下操作:

  1. 找出剩余的硬币中可以容纳的最大硬币是多少
  2. 考虑如果 (A) 包含该硬币或 (B) 不包含该硬币会发生什么。
  3. 对于每个场景,递归。

因此,如果余数为 50,最大的硬币价值 25 和 10,则您将分为两种情况:

1. Remainder = 25, Coinset = 1x25
2. Remainder = 50, Coinset = 0x25

下一步(对于每个分支)可能如下所示:

1-1. Remainder = 0,  Coinset = 2x25 <-- Note: Remainder=0 => Logged
1-2. Remainder = 25, Coinset = 1x25
2-1. Remainder = 40, Coinset = 0x25, 1x10
2-2. Remainder = 50, Coinset = 0x25, 0x10

每个分支将分为两个分支,除非:

  • 余数为 0(在在这种情况下你会记录它)
  • 余数小于最小的硬币(在这种情况下你会丢弃它)
  • 没有更多的硬币剩下(在这种情况下你会丢弃它,因为剩余!= 0)

This seems somewhat like a Partition, except that you don't use all integers in 1:50. It also seems similar to bin packing problem with slight differences:

Actually, after thinking about it, it's an ILP, and thus NP-hard.

I'd suggest some dynamic programming appyroach. Basically, you'd define a value "remainder" and set it to whatever your goal was (say, 50). Then, at every step, you'd do the following:

  1. Figure out what the largest coin that can fit within the remainder
  2. Consider what would happen if you (A) included that coin or (B) did not include that coin.
  3. For each scenario, recurse.

So if remainder was 50 and the largest coins were worth 25 and 10, you'd branch into two scenarios:

1. Remainder = 25, Coinset = 1x25
2. Remainder = 50, Coinset = 0x25

The next step (for each branch) might look like:

1-1. Remainder = 0,  Coinset = 2x25 <-- Note: Remainder=0 => Logged
1-2. Remainder = 25, Coinset = 1x25
2-1. Remainder = 40, Coinset = 0x25, 1x10
2-2. Remainder = 50, Coinset = 0x25, 0x10

Each branch would split into two branches unless:

  • the remainder was 0 (in which case you would log it)
  • the remainder was less than the smallest coin (in which case you would discard it)
  • there were no more coins left (in which case you would discard it since remainder != 0)
余生共白头 2024-11-12 03:05:40

如果您有 15、10、6 和 2 分硬币,并且您需要找出有多少种不同的方法可以达到 50,您可以

  • 仅使用 10、6 和 2
  • 来计算有多少种 不同的方法可以达到 50。仅使用 10、6 和 2 即可达到 50-15 的方法
  • 计算仅使用 10、6 和 2 即可达到 50-15*2 的不同方法有多少种
  • 计算如何有很多不同的方法,你只需要使用 10、6 和 2 就可以达到 50-15*3
  • 总结所有这些当然不同的结果(在第一个中我没有使用 15c 硬币,在第二个中我使用了一个,在第三个中两个)以及第四个三)。

所以你基本上可以将问题分成更小的问题(可能更小的数量和更少的硬币)。当您只有一种硬币类型时,答案当然是微不足道的(要么您无法准确达到规定的金额,要么您可以通过唯一可能的方式达到)。

此外,您还可以通过使用记忆来避免重复相同的计算,例如仅使用 [6, 2] 达到 20 的方法数量并不取决于是否使用 15+15 或 10+10+ 达到已支付的 30 10,所以较小问题 (20, [6, 2]) 的结果可以
被储存和重复使用。

在Python中这个想法的实现如下

cache = {}

def howmany(amount, coins):
    prob = tuple([amount] + coins) # Problem signature
    if prob in cache:
        return cache[prob] # We computed this before
    if amount == 0:
        return 1 # It's always possible to give an exact change of 0 cents
    if len(coins) == 1:
        if amount % coins[0] == 0:
            return 1 # We can match prescribed amount with this coin
        else:
            return 0 # It's impossible
    total = 0
    n = 0
    while n * coins[0] <= amount:
        total += howmany(amount - n * coins[0], coins[1:])
        n += 1
    cache[prob] = total # Store in cache to avoid repeating this computation
    return total

print howmany(50, [15, 10, 6, 2])

If you have 15, 10, 6 and 2 cents coins and you need to find how many distinct ways are there to arrive to 50 you can

  • count how many distinct ways you have to reach 50 using only 10, 6 and 2
  • count how many distinct ways you have to reach 50-15 using only 10, 6 and 2
  • count how many distinct ways you have to reach 50-15*2 using only 10, 6 and 2
  • count how many distinct ways you have to reach 50-15*3 using only 10, 6 and 2
  • Sum up all these results that are of course distinct (in the first I used no 15c coins, in the second I used one, in the third two and in the fourth three).

So you basically can split the problem in smaller problems (possibly smaller amount and fewer coins). When you have just one coin type the answer is of course trivial (either you cannot reach the prescribed amount exactly or you can in the only possible way).

Moreover you can also avoid repeating the same computation by using memoization, for example the number of ways of reach 20 using only [6, 2] doesn't depend if the already paid 30 have been reached using 15+15 or 10+10+10, so the result of the smaller problem (20, [6, 2]) can
be stored and reused.

In Python the implementation of this idea is the following

cache = {}

def howmany(amount, coins):
    prob = tuple([amount] + coins) # Problem signature
    if prob in cache:
        return cache[prob] # We computed this before
    if amount == 0:
        return 1 # It's always possible to give an exact change of 0 cents
    if len(coins) == 1:
        if amount % coins[0] == 0:
            return 1 # We can match prescribed amount with this coin
        else:
            return 0 # It's impossible
    total = 0
    n = 0
    while n * coins[0] <= amount:
        total += howmany(amount - n * coins[0], coins[1:])
        n += 1
    cache[prob] = total # Store in cache to avoid repeating this computation
    return total

print howmany(50, [15, 10, 6, 2])
冷情 2024-11-12 03:05:40

至于问题的第二部分,假设您在文件 coins.txt 中有该字符串:

#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>

int main() {
    std::ifstream coins_file("coins.txt");
    std::vector<int> coins;
    std::copy(std::istream_iterator<int>(coins_file),
              std::istream_iterator<int>(),
              std::back_inserter(coins));
}

现在向量 coins 将包含可能的硬币值。

As for the second part of your question, suppose you have that string in the file coins.txt:

#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>

int main() {
    std::ifstream coins_file("coins.txt");
    std::vector<int> coins;
    std::copy(std::istream_iterator<int>(coins_file),
              std::istream_iterator<int>(),
              std::back_inserter(coins));
}

Now the vector coins will contain the possible coin values.

触ぅ动初心 2024-11-12 03:05:40

对于如此少量的硬币,您可以编写一个简单的暴力解决方案。

像这样的东西:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

vector<int> v;

int solve(int total, int * coins, int lastI)
{
    if (total == 50) 
    {
        for (int i = 0; i < v.size(); i++)
        {
            cout << v.at(i) << ' ';
        }
        cout << "\n";
        return 1;
    }

    if (total > 50) return 0;

    int sum = 0;

    for (int i = lastI; i < 6; i++)
    {
        v.push_back(coins[i]);
        sum += solve(total + coins[i], coins, i); 
        v.pop_back();
    }

    return sum;
}


int main()
{
    int coins[6] = {2, 4, 6, 10, 15, 50};
    cout << solve(0, coins, 0) << endl;
}

一个非常肮脏的暴力解决方案,打印所有可能的组合。

这是一个非常著名的问题,因此请尝试阅读其他人提供的更好的解决方案。

For such a small number of coins you can write a simple brute force solution.

Something like this:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

vector<int> v;

int solve(int total, int * coins, int lastI)
{
    if (total == 50) 
    {
        for (int i = 0; i < v.size(); i++)
        {
            cout << v.at(i) << ' ';
        }
        cout << "\n";
        return 1;
    }

    if (total > 50) return 0;

    int sum = 0;

    for (int i = lastI; i < 6; i++)
    {
        v.push_back(coins[i]);
        sum += solve(total + coins[i], coins, i); 
        v.pop_back();
    }

    return sum;
}


int main()
{
    int coins[6] = {2, 4, 6, 10, 15, 50};
    cout << solve(0, coins, 0) << endl;
}

A very dirty brute force solution that prints all possible combinations.

This is a very famous problem, so try reading about better solutions others have provided.

长梦不多时 2024-11-12 03:05:40

一种相当愚蠢的方法如下。您构建一个映射“价值 X 的硬币被使用 Y 次”,然后枚举所有可能的组合,并仅选择那些总计达到所需总和的组合。显然,对于每个值 X,您必须检查 Y 的范围从 0 到所需的总和。这会相当慢,但会解决你的任务。

One rather dumb approach is the following. You build a mapping "coin with value X is used Y times" and then enumerate all possible combinations and only select those which total the desired sum. Obviously for each value X you have to check Y ranging from 0 up to the desired sum. This will be rather slow, but will solve your task.

夏花。依旧 2024-11-12 03:05:40

它与背包问题非常相似

It's very similar to the knapsack problem

青芜 2024-11-12 03:05:40

您基本上必须求解以下方程:50 = a*4 + b*6 + c*10 + d*15,其中未知数为 a、b、c、d。例如,您可以计算每个变量的 d = (50 - a*4 - b*6 - c*10)/15 等。然后,你开始给 d 所有可能的值(你应该从具有最小可能值的那个开始,这里是 d):0,1,2,3,4,然后根据当前的情况开始给 c 所有可能的值d 的值等等。

You basically have to solve the following equation: 50 = a*4 + b*6 + c*10 + d*15, where the unknowns are a,b,c,d. You can compute for instance d = (50 - a*4 - b*6 - c*10)/15 and so on for each variable. Then, you start giving d all the possible values (you should start with the one that has the least possible values, here d): 0,1,2,3,4 and than start giving c all the possible values depending on the current value of d and so on.

等风来 2024-11-12 03:05:40

将列表向后排序:[15 10 6 4 2]

现在 50 克拉的解决方案可以包含或不包含 15 克拉。
因此,解决方案的数量是使用 [10 6 4 2] 的 50 克拉的解决方案数量(不再考虑 15 克拉硬币)加上 使用的 35 克拉 (=50ct - 15ct) 的解决方案数量[15 10 6 4 2]。对两个子问题重复该过程。

Sort the List backwards: [15 10 6 4 2]

Now a solution for 50 ct can contain 15 ct or not.
So the number of solutions is the number of solutions for 50 ct using [10 6 4 2] (no longer considering 15 ct coins) plus the number of solutions for 35 ct (=50ct - 15ct) using [15 10 6 4 2]. Repeat the process for both sub-problems.

酒几许 2024-11-12 03:05:40

算法是解决问题的过程,它不必采用任何特定的语言。

首先计算出输入:

typedef int CoinValue;

set<CoinValue> coinTypes;
int value;

和输出:

set< map<CoinValue, int> > results;

首先解决您能想到的最简单的情况:

coinTypes = { 1 }; // only one type of coin worth 1 cent
value = 51;

结果应该是:

results = { [1 : 51] }; // only one solution, 51 - 1 cent coins

您将如何解决上述问题?

这个怎么样:

coinTypes = { 2 };
value = 51;

results = { }; // there is no solution

这个怎么样?

coinTypes = { 1, 2 };
value = { 4 };

results = { [2: 2], [2: 1, 1: 2], [1: 4] }; // the order I put the solutions in is a hint to how to do the algorithm.

An algorithm is a procedure for solving a problem, it doesn't have to be in any particular language.

First work out the inputs:

typedef int CoinValue;

set<CoinValue> coinTypes;
int value;

and the outputs:

set< map<CoinValue, int> > results;

Solve for the simplest case you can think of first:

coinTypes = { 1 }; // only one type of coin worth 1 cent
value = 51;

the result should be:

results = { [1 : 51] }; // only one solution, 51 - 1 cent coins

How would you solve the above?

How about this:

coinTypes = { 2 };
value = 51;

results = { }; // there is no solution

what about this?

coinTypes = { 1, 2 };
value = { 4 };

results = { [2: 2], [2: 1, 1: 2], [1: 4] }; // the order I put the solutions in is a hint to how to do the algorithm.
谈场末日恋爱 2024-11-12 03:05:40

基于 Scala 中的 algorithmist.com 资源的递归解决方案:

def countChange(money: Int, coins: List[Int]): Int = {
    if (money < 0 || coins.isEmpty) 0
    else if (money == 0) 1
    else countChange(money, coins.tail) + countChange(money - coins.head, coins)
}

Recursive solution based on algorithmist.com resource in Scala:

def countChange(money: Int, coins: List[Int]): Int = {
    if (money < 0 || coins.isEmpty) 0
    else if (money == 0) 1
    else countChange(money, coins.tail) + countChange(money - coins.head, coins)
}
回忆躺在深渊里 2024-11-12 03:05:40

另一个Python版本:

def change(coins, money):
    return (
        change(coins[:-1], money) +
        change(coins, money - coins[-1])
        if money > 0 and coins
        else money == 0
    )

Another Python version:

def change(coins, money):
    return (
        change(coins[:-1], money) +
        change(coins, money - coins[-1])
        if money > 0 and coins
        else money == 0
    )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文