我试图解决一个算法问题,该问题涉及计算给定数组中平方数组排列的数量。当且仅当每对相邻元素的总和是完全平方时,数组才是平方的。
我尝试使用位掩码 DP 来解决这个问题。其中表示以二进制格式表示的以状态dp[i][j]
结尾的方形数组的数量(例如,1001111,其中 1 是已访问的节点,而 0 不是)。下面是两个版本的代码:j
i
int n = nums.length;
int[][] dp = new int[1 << n][n];
Arrays.sort(nums);
for (int k = 0; k < n; k++) {
if(k == 0 || (k > 0 && nums[k - 1] != nums[k])) {
dp[1 << k][k] = 1;
}
}
// first version of dp traversal
for(int s = 0; s < (1 << n); s++) {
for(int j = 0; j < n; j++) {
if((s & (1 << j)) == 0) continue;
for(int p = 0; p < n; p++) {
int d = (int)Math.floor(Math.sqrt(nums[p] + nums[j]));
if(!(d * d == nums[p] + nums[j])) continue;
if((s & (1 << p)) != 0) continue;
if(p > 0 && nums[p] == nums[p - 1] && (s & (1 << (p - 1))) == 0) continue;
dp[s | (1 << p)][p] += dp[s][j];
}
}
}
// second version of dp traversal
for(int s = 0; s < (1 << n); s++) {
for(int j = 0; j < n; j++) {
if((s & (1 << j)) == 0) continue;
for(int p = 0; p < n; p++) {
int d = (int)Math.floor(Math.sqrt(nums[p] + nums[j]));
if(!(d * d == nums[p] + nums[j])) continue;
if((s & (1 << p)) != 0) continue;
if((((s & ~(1 << j)) & (1 << p)) == 0)) continue;
if(p > 0 && nums[p] == nums[p - 1] && (s & (1 << (p - 1))) == 0) continue;
dp[s][j] += dp[(s & ~(1 << j))][p];
}
}
}
int ans = 0;
for(int l = 0; l < n; l++) {
ans += dp[(1 << n) - 1][l];
}
return ans;
我感到困惑的是:当我尝试运行代码时,第一个版本给出了正确的结果,而第二个版本没有。我认为dp[s][j] += dp[(s & ~(1 << j))][p]
意味着s
结束状态j
s
没有j
那个状态的所有结果的总和是否以p
ifp
和j
are connected 结尾?