c++ - 给定硬币的所有可能总和

标签 c++ algorithm set bit-manipulation dynamic-programming

您有 n 个具有特定值(value)的硬币。您的任务是找到使用这些硬币可以创造的所有金额。

输入

第一行输入有一个整数n:硬币数量。

下一行有 n 个整数 x1,x2,…,xn:硬币的值。

输出

首先打印一个整数k:不同货币总和的数量。之后,按升序打印所有可能的总和。

约束

1≤n≤100
1≤xi≤1000

示例

输入:

4
4 2 5 2

输出:

9
2 4 5 6 7 8 9 11 13

我编写了一个代码,该代码对于小输入非常有效,但对于大输入给出了错误的答案。请帮忙找出错误以及如何纠正。

我的代码是:

#include <bits/stdc++.h>
using namespace std;

set<long long> s;
// Prints sums of all subsets of array
void subsetSums(long long arr[], long long n)
{
    // There are totoal 2^n subsets
    long long total = 1 << n;

    // Consider all numbers from 0 to 2^n - 1
    for (long long i = 0; i < total; i++)
    {
        long long sum = 0;

        // Consider binary reprsentation of
        // current i to decide which elements
        // to pick.
        for (long long j = 0; j < n; j++)
            if (i & (1 << j))
                sum += arr[j];

        // Print sum of picked elements.
        if (sum)
            s.insert(sum);
    }
}

// Driver code
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    long long n;
    cin >> n;
    long long arr[n];
    for (long long i = 0; i < n; i++)
    {
        cin >> arr[i];
    }
    subsetSums(arr, n);
    cout << s.size() << "\n";
    for (auto it = s.begin(); it != s.end(); ++it)
        cout << *it << " ";
    return 0;
}

例如,它给出了错误的答案

50
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 

作为

18
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36

正确的输出应该是:

50
1 2 3 4 ... 50

最佳答案

你的代码太慢2^n子集在最坏的情况下(当n=100)给出1,267,650,600,228,229,401,496,703,205,376子集,而C++ 平均每秒执行大约 1000,000,000 次操作。

这个问题可以用动态规划来解决,考虑有一个大小为100001的数组dp,这样dp[x]表示如果x 的总和是可以实现的。

基本情况很简单 - 不使用任何硬币就可以得到 0 的总和:dp[0]=1

然后,对于每种硬币,我们可以尝试按硬币值(value)增加现有金额以填满我们的表格:

for each coinValue:
for coinSum = 100000 - coinValue; coinSum >=0; coinSum--)
    if(dp[coinSum])
    dp[coinSum + coinValue]=1

请注意,我们正在向后循环,这是故意这样做的,以便每个硬币仅使用一次。

复杂度:O(n^2*maxCoinValue)

关于c++ - 给定硬币的所有可能总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62357952/

相关文章:

algorithm - 通过折叠然后除以素数来散列 key ?

algorithm - 关于后缀数组的原始论文中的勘误表?

python - 查找哪个对象不在列表中,但可能有重复项...棘手

c++ - 为什么我用 Boost.ASIO 实现的简单 HTTP 服务器需要 sleep 才能正常工作

c++ - 我无法构建需要 WOW64 Api 的库

algorithm - Big-O 和缓存感知数据结构和算法

c++ - multimap 与带集合的 map

c++ - std::unordered_set::find - 仅为 find() 构造一个实例

c++ - 使用类修改字节中的位

c++ pthreads和struct的损坏数据