📜  数组和最多为 N 的子集和问题

📅  最后修改于: 2022-05-13 01:56:04.595000             🧑  作者: Mango

数组和最多为 N 的子集和问题

给定一个大小为N的数组arr[] ,使得所有数组元素的总和不超过 N,并且数组queries[]包含Q个查询。对于每个查询,任务是查找是否存在数组的子集,其总和与query[i]相同。

例子:

方法:可以使用子集和问题中的方法来解决问题。
但是,可以使用总和最多为N的事实来降低时间复杂度。由于总和最多为 N,因此可以证明最多有√2N 个唯一的正元素,其中所有的频率都为 1。

上述事实可以在动态规划中使用和实现。使用坐标压缩,所有这些独特的元素都可以存储在最小的空间中。

按照下图可以更好地理解正常子集的未使用状态以及总和为 N 时的最大差异:

比较:

按照下面提到的步骤实施该方法;

  • 对所有独特元素使用坐标压缩
  • 构建一个二维 dp[][] 数组,其中dp[i][j]存储第 i项的贡献以获得总和j 。 (如果不可能,则存储 - 1 ,如果不需要第 i 个项目,则将0存储在dp[i][j]中)。
  • i = 0 迭代到最大元素:
    • 迭代j = 0 到 N
      • 如果 dp[i][j-arr[i]] + 1 < dp[i][j] 的值,则更新它。
      • 否则,保持原样。
  • 然后从 i = 0 迭代到 Q:
    • 检查该总和 (query[i]) 是否可能。
    • 如果它超过数组总和或所有元素一起无法获得某个总和,即dp[len][query[i]] = -1 ,则这是不可能的。 (len 是唯一元素元素的总数)

下面是上述方法的实现。

C++
// C++ code to implement the approach
  
#include 
using namespace std;
  
// Function to find if the queries
// are possible or not
void findSol(vector& arr,
             vector& queries)
{
    int s = 0;
  
    // Calculating sum of array
    for (auto& item : arr) {
        s += item;
    }
  
    // Coordinate compression,
    // make frequency-value pairs
    map mp;
    for (auto& item : arr) {
        mp[item]++;
    }
  
    vector val, freq;
  
    // Frequency mapping
    for (auto& x : mp) {
        val.push_back(x.first);
        freq.push_back(x.second);
    }
  
    int len = val.size();
    vector > dp(len + 1,
                            vector(
                                s + 1, 0));
  
    for (int j = 1; j <= s; ++j) {
        dp[0][j] = -1;
    }
  
    // Loop to build the dp[][]
    for (int i = 1; i <= len; ++i) {
        for (int j = 1; j <= s; ++j) {
            int v = val[i - 1];
            int f = freq[i - 1];
  
            if (dp[i - 1][j] != -1) {
                dp[i][j] = 0;
            }
            else if (j >= v
                     && dp[i][j - v] != -1
                     && dp[i][j - v] + 1 <= f) {
                dp[i][j] = dp[i][j - v] + 1;
            }
            else {
                dp[i][j] = -1;
            }
        }
    }
  
    // Answer queries
    for (auto& q : queries) {
        if (q > s || dp[len][q] == -1) {
            cout << "Not Possible" << endl;
        }
        else {
            cout << "Possible" << endl;
        }
    }
}
  
// Driver Code
int main()
{
    vector arr = { 1, 0, 0, 0, 0, 2, 3 };
    vector queries = { 3, 7, 6 };
  
    // Function call
    findSol(arr, queries);
    return 0;
}


输出
Possible
Not Possible
Possible

时间复杂度:O(N * √N)
辅助空间: O(N * √N)