给定长度为n的数组,找到子集的XOR等于给定数量的子集的数量

时间:2015-12-08 05:34:39

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

给定长度为arr的数组n,找出arr的子集数量,使得这些子集的XOR(^)等于给定数量, ans

我有这种dp方法,但有办法改善其时间复杂度。 ans始终小于1024。

这里ans是否定的。使XOR(^)个子集等于它。 arr[n]包含所有数字

memset(dp, 0, sizeof(dp));
dp[0][0] = 1;

for(i = 1; i <= n; i++){
    for(j = 0; j < 1024; j++) {
        dp[i][j] = (dp[i-1][j] + dp[i-1][j^arr[i]]);
    }
}

cout << (dp[n][ans]);

2 个答案:

答案 0 :(得分:2)

来自user3386109的评论,建立在您的代码之上:

/* Warning: Untested */
int counts[1024] = {0}, ways[1024];
for(int i = 1; i <= n; ++i) counts[ arr[i] ] += 1;
for(int i = 0; i <= 1024; ++i) {
  const int z = counts[i];
  // Look for overflow here
  ways[i] = z == 0 ?
              0 :
              (int)(1U << (z-1));
}

memset(dp, 0, sizeof(dp));
dp[0][0] = 1;

for(i = 1; i <= 1024; i++){
    for(j = 0; j < 1024; j++) {
        // Check for overflow
        const int howmany = ways[i] * dp[i-1][j];
        dp[i][j] += howmany;
        dp[i][j^i] += howmany;
    }
}

cout << (dp[1024][ans]);

要计算odd_even_,您还可以使用以下内容:

  

n c 0 + n c 2 + ... =    n c 1 + n c 3 ... =   2 N-1

因为选择奇数项目的方式数量=拒绝奇数项目的方式数量=选择偶数数字的方式数量

您还可以通过仅保留2列dp数组来优化空间,并将dp[i-2][x]作为let locations = response as! [ESTLocation] 重新使用。

答案 1 :(得分:1)

动态编程背后的理念是,(1)永远不会计算两次相同的结果,(2)只根据需要计算结果,而不是像你那样预先计算整个事物。

因此solve(arr, n, ans) ans < 1024n < 1000000arr = array[n]需要一个解决方案。让dp[n][ans]保持结果数量的想法是合理的,因此需要dp大小为dp = array[n+1][1024]。我们需要的是一种区分尚未计算的结果和可用结果的方法。那么memset(dp, -1, sizeof(dp))然后就像你已经dp[0][0] = 1

那样
solve(arr, n, ans):
    if (dp[n][ans] == -1)
        if (n == 0) // and ans != 0 since that was initialized already
            dp[n][ans] = 0
        else
            // combine results with current and without current array element
            dp[n][ans] = solve(arr + 1, n - 1, ans) + solve(arr + 1, n - 1, ans XOR arr[0])
    return dp[n][ans]

优点是,您的dp数组仅在您的解决方案的路上部分计算,因此这可能会节省一些时间。

根据堆栈大小和n,可能需要将其从递归解决方案转换为迭代解决方案