给定长度为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]);
答案 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 < 1024
,n < 1000000
和arr = 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
,可能需要将其从递归解决方案转换为迭代解决方案