排列法求解8皇后问题程序误输出非解排列的问题排查
问题背景
需要编写基于排列法的8皇后问题求解程序,目前代码已经可以生成8位数字的全排列,但会输出不符合8皇后规则的非法解,无法定位问题原因。
对应实现代码如下:
class formPermut { int[] row = new int[8]; int ifGoodPermutation = 1; public void swapNumbers(ref int a, ref int b) { int temp = a; a = b; b = temp; } public void PrintPermutation(int[] list, int k, int m) { int i; if (k == m) { for (i = 0; i <= m; i++) { row[i] = list[i]; } for (int g = 0; g <= m; g++)//column { for (int j = g + 1; j <= m; j++) { if ((row[g] + j) == row[j]) { ifGoodPermutation = 0; break; } else if((row[g] - j) == [j]) { ifGoodPermutation = 0; break; } } if (ifGoodPermutation == 0) break; } if (ifGoodPermutation == 1) { for (i = 0; i <= m; i++) { Console.Write(row[i]); Console.Write(" "); } Console.WriteLine(); } } else { for (i = k; i <= m; i++) { swapNumbers(ref list[k], ref list[i]); ifGoodPermutation = 1; PrintPermutation(list, k + 1, m); swapNumbers(ref list[k], ref list[i]); } } } }
问题定位
代码共有3处错误,直接导致合法性校验失效:
- 对角线冲突判定逻辑完全错误。8皇后规则中,两个皇后共对角线的判定条件是两位置行号差的绝对值等于列号差的绝对值,现有代码用
row[g] +j == row[j]、row[g]-j == [j]做判断,没有计算两列的索引差,根本无法识别对角线冲突。 - 存在笔误。第二个判断分支里写的
[j]是无效写法,漏写了数组名row,原本应该取row[j]的值。 - 合法标记重置位置错误。
ifGoodPermutation标记仅在递归交换元素时重置,在进入叶子节点、开始校验排列合法性前没有重置,会沿用上一次校验的标记值,导致漏判、错判。
修复方法
将叶子节点的校验逻辑替换为如下代码即可:
if (k == m) { for (i = 0; i <= m; i++) { row[i] = list[i]; } // 每次校验前先重置合法标记 ifGoodPermutation = 1; for (int g = 0; g <= m; g++) { for (int j = g + 1; j <= m; j++) { // 正确判定对角线冲突 if (Math.Abs(row[g] - row[j]) == Math.Abs(g - j)) { ifGoodPermutation = 0; break; } } if (ifGoodPermutation == 0) break; } if (ifGoodPermutation == 1) { for (i = 0; i <= m; i++) { Console.Write(row[i]); Console.Write(" "); } Console.WriteLine(); } }
修复后程序会正确输出全部92个8皇后合法解,不会再输出非法排列。
内容的提问来源于stack exchange,提问作者alex
相关产品推荐
相关产品推荐

