【问题标题】:Given an array of integers, find the subset sum closest to K给定一个整数数组,找到最接近 K 的子集和
【发布时间】:2021-05-23 04:15:52
【问题描述】:

我知道这是一个重量和值相等的背包问题,但我认为我在编码逻辑中犯了一个错误,因为即使对于数组中的元素数量(N ) 为 50,所需的最大总和 (M) 为 4500。

为了澄清问题,给定一个由 N 个正整数和一个正整数 M 组成的数组。数组元素只能使用一次。 我们必须找到这个数组的一个子集(不一定是连续的),使得总和最接近 M 但不超过它。

这是我使用动态编程的尝试:

int M, N, price[100];
int memo[5000][100];

int dp(int left, int g)
{
    if (left < 0)
        return -10000000;

    if (g == N)
        return M - left;

    if (memo[left][g] != -1)
        return memo[left][g];

    int ans = -1;

    ans = max(ans, dp(left - price[g], g + 1));
    ans = max(ans, dp(left, g + 1));
    //cout<<g<<ln;
    return memo[left][g] = ans;
}

void solve()
{

    cin >> M >> N;

    forn(i, N)
    {
        cin >> price[i];
    }
    int score;
    memset(memo, -1, sizeof memo);
    score = dp(M, 0);
    //print_dp(M,0);

    if (score < 0)
        cout << "NO SOLUTION";
    else
        cout << score << ln;
}

int main(){
    solve();
    return 0;
}

那么在我的代码中是否有任何可能的优化可以帮助我降低复杂性,因为这甚至不是最大的测试用例,有一个 M = 10^9 的测试用例。 以及如何跟踪解决方案的实际子集,因为在这里我只是返回最终的最大可能总和。 任何指导将不胜感激! 谢谢

【问题讨论】:

    标签: algorithm subset dynamic-programming knapsack-problem subset-sum


    【解决方案1】:

    考虑下一个代码 (ideone)。

    对于每个价格 (p),它会检查 memo 数组的所有单元格并标记单元格 j,如果可以将值 j 与 p 和一些先前的总和 j-p 组合在一起。它还更新jmax - 最大可能总和并将其作为结果返回。对于数据集 M=9 N=4 {2 3 5 11},它给出了 8 尽可能多的数组项总和 (&lt;=9)。

    #include <iostream>
    #include <cstring>
    using namespace std;
    int M, N, p;
    int memo[5000];
    
    int solve()
    {
    
        cin >> M >> N;
        int i, j, jmax = 0;
    
        memset(memo, 0, sizeof(memo));
        memo[0] = 1;
        for(i = 0; i < N; i++) {
            cin >> p;
            for(j=M; j>=p; j--){
                if(memo[j-p]) {
                   memo[j]=1;
                   if(j>jmax)
                     jmax = j;
                }
            }
        }
        return jmax;
    }
    
    int main(){
        std::cout<<solve();
        return 0;
    }
    

    【讨论】:

    • 哇,这是一个很好的答案!但是正如我在问题中提到的,有大小为 10^9 的数据集,我们在这里基本上需要一个大小为 10^9 的数组,由于某种原因,编译器抛出了一个“错误:数组的大小 '4000000028' memo' 超过最大对象大小 '2147483647' int memo[1000000007]; "
    • pastebin.com/YUcWThEv这里是测试用例供参考
    • @Banana Bamboo 对于较大的 M 值和较小的 N,我们可以使用字典(映射)而不是数组,因此只会存储现有的总和。
    • 为了避免扫描到 M 的所有值,在大 M 的情况下构建新地图,将 p 添加到当前地图中的每个值。
    猜你喜欢
    • 2019-06-04
    • 2014-07-29
    • 2013-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多