我正在尝试解决一个棘手的问题。这是一个零钱的找零问题。
如果获得总和,请找到可以在两个人之间平均共享的独特组合。
例如,如果给定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;
};
答案 0 :(得分:0)
仅当总数为偶数时,解决方案才有可能,否则您显然不能一分为二。
我们的目标不是重新发明轮子,这与Knapsack Problem一样,所有硬币的权重都相同。例如,价值3的硬币的权重为3,价值1的硬币的权重为1。您的目标是:
1-找到一个(或一组)最佳解决方案以装满容量一半(人1)的背包。
2-剩余的未被选择的硬币将自动分配给第2个人,并且将是有效的组合。
背包将尝试将背包装满至最大值,从而达到最大容量。
如果这达到最大容量,即总量/ 2,则该问题可以解决。如果命中率更低,则不会。