所有可能幻方解法使用回溯
程序员文章站
2022-05-18 20:52:28
...
幻方 指N^2 格子放入所有1-N^2 的数子 使得格子水平列、垂直行或对角线数字和相同
求得所有可能
使用回溯法
public class Magiques {
int max, sumNum, n;
public List<String> desQuassez(int n) {
List<String> res = new ArrayList<>();
if (n < 1) return res;
int[][] board = new int[n][n];
this.n = n;
max = n * n;
sumNum = (max + 1) * n / 2;
boolean[] allUsed = new boolean[n * n];
int[] colSum = new int[n];
int[] rowSum = new int[n];
int forwardSum = 0;
int inverseSum = 0;
recurse(res, 0, board, allUsed, colSum, rowSum, forwardSum, inverseSum);
return res;
}
/**
* 递归求解
* @param res 结果
* @param fixN 第N个格子
* @param board 填充数字的格子
* @param allUsed 使用过的数字 allUsed[i] = true 指 第i个数字已被使用
* @param colSum 列的和
* @param rowSum 行的和
* @param forward 正斜线的和
* @param inverseSum 逆斜线的和
*/
private void recurse(List<String> res,int fixN, int[][] board, boolean[] allUsed, int[] colSum, int[] rowSum, int forwardSum, int inverseSum) {
int row = fixN / n;
int col = fixN % n;
if (col > 0 && row == n - 1 && colSum[col - 1] != sumNum) return;
if (fixN >= n && col == 0 && rowSum[row - 1] != sumNum) return;
if (row == n - 1 && col > 0 && inverseSum != sumNum) return;
if (fixN == max) {
if (forwardSum != sumNum) return;
res.add(Arrays.deepToString(board));
return;
}
for (int i = 1; i <= max; i++) {
if (allUsed[i - 1]) continue;
allUsed[i - 1] = true;
board[row][col] = i;
colSum[col] += i;
rowSum[row] += i;
if (col == row) forwardSum += i;
if (col + row == n - 1) inverseSum += i;
recurse(res, fixN + 1, board, allUsed, colSum, rowSum, forwardSum, inverseSum);
if (col == row) forwardSum -= i;
if (col == n - row - 1) inverseSum -= i;
colSum[col] -= i;
rowSum[row] -= i;
board[row][col] = 0;
allUsed[i - 1] = false;
}
}
public static void main(String[] args) {
Magiques testInstance = new Magiques();
List<String> res = testInstance.desQuassez(4);
res.stream().forEach(o -> System.out.println(o));
System.out.println(res.size());
}
}
上一篇: PHP 核心特性 - 错误处理
推荐阅读