两个人共享的硬币组合

时间:2018-06-23 07:59:26

标签: c++ combinations

我正在尝试解决一个棘手的问题。这是一个零钱的找零问题。

如果获得总和,请找到可以在两个人之间平均共享的独特组合。

例如,如果给定6,而您无限供应1p和2p硬币,则会得到以下组合:
111 ... 111
12 .... 12
22 .... 11
11 .... 22

想象一下将硬币分隔在两个人之间的中心线。

我有一个有效的递归C ++解决方案。它遍历数组并尝试每个位置的每个硬币,如果没有它。它可以工作,但是当给定的总和很大时效率不高。

有DP解决方案吗?但是,这不是直接找到组合数量的问题。

有人可以帮忙吗?

我的代码是:

unsigned long long CalculateCombinations(std::vector<int> &denominations, std::vector<int> change, int amount, unsigned int index)
{
    unsigned long long combinations = 0;

    if (amount <= 0)
        return combinations;

    std::stack<Param> mystack;
    mystack.push({ change, amount, index });

    while (!mystack.empty())
    {
        int current = 0;
        std::vector<int> current_coins = mystack.top().Coins;
        int current_amount = mystack.top().Amount;
        unsigned int current_index = mystack.top().Index;
        mystack.pop();

        if (current_amount == 0)
        {
            if (current_coins.size() % 2 == 0)
            {
                combinations += CalculateCombinations(std::move(current_coins));
            }
        }
        else
        {
            std::string str = std::to_string(current_amount) + "-" + std::to_string(current_index);
            if (Memo.find(str) == Memo.end())
            {
                // If amount is less than 0 then no solution exists
                if (current_amount >= 0 && current_index < denominations.size())
                {
                    while (current <= current_amount)
                    {
                        int remainder = current_amount - current;
                        mystack.push({ current_coins, remainder, current_index + 1 });
                        current += denominations[current_index];
                        current_coins.push_back(denominations[current_index]);
                    }
                }
                else
                {
                    Memo.insert(str);
                }
            }
        }
    }

    return combinations;
}

并且:

std::unordered_set<std::string> Memo;

struct Param {
    std::vector<int> Coins;
    int Amount;
    unsigned int Index;
};

1 个答案:

答案 0 :(得分:0)

仅当总数为偶数时,解决方案才有可能,否则您显然不能一分为二。

我们的目标不是重新发明轮子,这与Knapsack Problem一样,所有硬币的权重都相同。例如,价值3的硬币的权重为3,价值1的硬币的权重为1。您的目标是:

1-找到一个(或一组)最佳解决方案以装满容量一半(人1)的背包。

2-剩余的未被选择的硬币将自动分配给第2个人,并且将是有效的组合。

背包将尝试将背包装满至最大值,从而达到最大容量。

如果这达到最大容量,即总量/ 2,则该问题可以解决。如果命中率更低,则不会。