【问题标题】:Count number of subsets with sum equal to k计算总和等于 k ​​的子集数
【发布时间】:2014-05-18 10:28:15
【问题描述】:

给定一个数组,我们需要找出总和恰好等于给定整数 k 的子集的数量。 请为这个问题提出一个最佳算法。这里不需要实际的子集,只需要计数即可。

数组由整数组成,可以是负数也可以是非负数。

示例: 数组 -> {1,4,-1,10,5} abs sum->9 {4,5} 和 {-1,10}

的答案应该是 2

【问题讨论】:

  • 你有没有尝试过?有什么第一想法吗?
  • 你的数组中有负数吗?整数还是浮点数?有什么尝试吗?
  • subarrays 存在多项式解。您的子集是否意味着 subarray ?请举个例子。

标签: algorithm count subset-sum


【解决方案1】:

这是subset sum problem 的变体,即NP-Hard - 所以没有已知的多项式解决方案。 (事实上​​,子集和问题是很难找到是否有一个子集与给定的和相加)。

解决它的可能方法是蛮力(检查所有可能的子集),或者如果集合包含相对较小的整数,您可以使用伪多项式动态规划技术:

f(i,0) = 1    (i >= 0) //succesful base clause
f(0,j) = 0    (j != 0) //non succesful base clause
f(i,j) = f(i-1,j) + f(i-1,j-arr[i])  //step

对上面的递归公式应用动态规划可以得到O(k*n)时空解。

使用 f(n,k) 调用 [假设数组的索引基于 1]。

【讨论】:

  • 使用距离列表可以帮助L={1,2,3,0,-3,-5,-6} g=2 然后D(g,L) = {-1,0,+1,-2,-5,-7,-8}
  • 但是这个算法不计算子集的数量。这个算法只告诉你是否有解决方案。即使在那之后并应用回溯,您也可以得出一个解决方案。不是所有的解决方案。
【解决方案2】:

以下是记忆的动态编程代码,用于打印具有给定总和的子集数量的计数。 DP 的重复值存储在“tmp”数组中。要获得 DP 解决方案,首先总是从问题的递归解决方案开始,然后将重复值存储在 tmp 数组中以获得记忆解决方案。

#include <bits/stdc++.h>

using namespace std; 

int tmp[1001][1001];  


int subset_count(int* arr, int sum, int n) 
{ ` if(sum==0)
        return 1;
    if(n==0)
        return 0;
    if(tmp[n][sum]!=-1)
        return tmp[n][sum];
    else{
        if(arr[n-1]>sum)
            return tmp[n][sum]=subset_count(arr,sum, n-1);
        else{
            return tmp[n][required_sum]=subset_count(arr,sum, n- 1)+subset_count(arr,sum-arr[n-1], n-1);`
        }
    }
} 

// Driver code 

int main() 
{ ` memset(tmp,-1,sizeof(tmp));
    int arr[] = { 2, 3, 5, 6, 8, 10 }; 
    int n = sizeof(arr) / sizeof(int); 
    int sum = 10; `


    cout << subset_count(arr,sum, n); 

    return 0; 
}

【讨论】:

    【解决方案3】:

    这是递归解决方案。它的时间复杂度为 O(2^n) 使用动态规划将时间复杂度提高到二次 O(n^2)

    def count_of_subset(arr,sum,n,count):
        if sum==0:
            count+=1
            return count
        if n==0 and sum!=0:
            count+=0
            return count
        if arr[n-1]<=sum:
            count=count_of_subset(arr,sum-arr[n-1],n-1,count)
            count=count_of_subset(arr,sum,n-1,count)
            return count
        else:
            count=count_of_subset(arr,sum,n-1,count)
            return count
    

    【讨论】:

    • 是 O(n^2) 时间还是 O(n*sum)?
    • 它是二次时间,即 O(2^n),因为它是一个递归解决方案,并且一次又一次地计算相同的问题
    • 你的意思是指数?二次方是 2 次方。
    • @GauriShankarBadola 是的!
    【解决方案4】:

    这个解决方案的一个答案是生成一个 N 的幂集,其中 N 是数组的大小,将等于 2^n。对于 0 到 2^N-1 之间的每个数字,检查其二进制表示并包括该位位于设置位置的数组中的所有值,即一个。 检查您包含的所有值的总和是否等于所需值。 这可能不是最有效的解决方案,但由于这是一个 NP 难题,因此该问题不存在多项式时间解决方案。

    【讨论】:

    • 这是一个幼稚的解决方案,不是最优的!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多