BAEL-1298 Dancing Links Algorithm. Smaller changes to Backtracking
This commit is contained in:
parent
3351d50a5a
commit
cbf7bcbbbf
@ -2,9 +2,7 @@ package com.baeldung.algorithms.sudoku;
|
|||||||
|
|
||||||
public class BacktrackingAlgorithm {
|
public class BacktrackingAlgorithm {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
static char[][] board = {
|
||||||
|
|
||||||
char[][] board = {
|
|
||||||
{ '8', '.', '.', '.', '.', '.', '.', '.', '.' },
|
{ '8', '.', '.', '.', '.', '.', '.', '.', '.' },
|
||||||
{ '.', '.', '3', '6', '.', '.', '.', '.', '.' },
|
{ '.', '.', '3', '6', '.', '.', '.', '.', '.' },
|
||||||
{ '.', '7', '.', '.', '9', '.', '2', '.', '.' },
|
{ '.', '7', '.', '.', '9', '.', '2', '.', '.' },
|
||||||
@ -16,9 +14,13 @@ public class BacktrackingAlgorithm {
|
|||||||
{ '.', '9', '.', '.', '.', '.', '4', '.', '.' }
|
{ '.', '9', '.', '.', '.', '.', '4', '.', '.' }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
|
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
|
||||||
solver.solve(board);
|
solver.solve(board);
|
||||||
|
solver.printBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printBoard() {
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
for (int j = 0; j < 9; j++) {
|
for (int j = 0; j < 9; j++) {
|
||||||
System.out.print(board[i][j] + " ");
|
System.out.print(board[i][j] + " ");
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.baeldung.algorithms.sudoku;
|
||||||
|
|
||||||
|
class ColumnNode extends DancingNode {
|
||||||
|
int size;
|
||||||
|
String name;
|
||||||
|
|
||||||
|
public ColumnNode(String n) {
|
||||||
|
super();
|
||||||
|
size = 0;
|
||||||
|
name = n;
|
||||||
|
C = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cover() {
|
||||||
|
unlinkLR();
|
||||||
|
for (DancingNode i = this.D; i != this; i = i.D) {
|
||||||
|
for (DancingNode j = i.R; j != i; j = j.R) {
|
||||||
|
j.unlinkUD();
|
||||||
|
j.C.size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uncover() {
|
||||||
|
for (DancingNode i = this.U; i != this; i = i.U) {
|
||||||
|
for (DancingNode j = i.L; j != i; j = j.L) {
|
||||||
|
j.C.size++;
|
||||||
|
j.relinkUD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relinkLR();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package com.baeldung.algorithms.sudoku;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DancingLinks {
|
||||||
|
|
||||||
|
private ColumnNode header;
|
||||||
|
private List<DancingNode> answer;
|
||||||
|
|
||||||
|
private void search(int k) {
|
||||||
|
if (header.R == header) {
|
||||||
|
handleSolution(answer);
|
||||||
|
} else {
|
||||||
|
ColumnNode c = selectColumnNodeHeuristic();
|
||||||
|
c.cover();
|
||||||
|
|
||||||
|
for (DancingNode r = c.D; r != c; r = r.D) {
|
||||||
|
answer.add(r);
|
||||||
|
|
||||||
|
for (DancingNode j = r.R; j != r; j = j.R) {
|
||||||
|
j.C.cover();
|
||||||
|
}
|
||||||
|
|
||||||
|
search(k + 1);
|
||||||
|
|
||||||
|
r = answer.remove(answer.size() - 1);
|
||||||
|
c = r.C;
|
||||||
|
|
||||||
|
for (DancingNode j = r.L; j != r; j = j.L) {
|
||||||
|
j.C.uncover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.uncover();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColumnNode selectColumnNodeHeuristic() {
|
||||||
|
int min = Integer.MAX_VALUE;
|
||||||
|
ColumnNode ret = null;
|
||||||
|
for (ColumnNode c = (ColumnNode) header.R; c != header; c = (ColumnNode) c.R) {
|
||||||
|
if (c.size < min) {
|
||||||
|
min = c.size;
|
||||||
|
ret = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColumnNode makeDLXBoard(boolean[][] grid) {
|
||||||
|
final int COLS = grid[0].length;
|
||||||
|
final int ROWS = grid.length;
|
||||||
|
|
||||||
|
ColumnNode headerNode = new ColumnNode("header");
|
||||||
|
ArrayList<ColumnNode> columnNodes = new ArrayList<ColumnNode>();
|
||||||
|
|
||||||
|
for (int i = 0; i < COLS; i++) {
|
||||||
|
ColumnNode n = new ColumnNode(Integer.toString(i));
|
||||||
|
columnNodes.add(n);
|
||||||
|
headerNode = (ColumnNode) headerNode.hookRight(n);
|
||||||
|
}
|
||||||
|
headerNode = headerNode.R.C;
|
||||||
|
|
||||||
|
for (int i = 0; i < ROWS; i++) {
|
||||||
|
DancingNode prev = null;
|
||||||
|
for (int j = 0; j < COLS; j++) {
|
||||||
|
if (grid[i][j] == true) {
|
||||||
|
ColumnNode col = columnNodes.get(j);
|
||||||
|
DancingNode newNode = new DancingNode(col);
|
||||||
|
if (prev == null)
|
||||||
|
prev = newNode;
|
||||||
|
col.U.hookDown(newNode);
|
||||||
|
prev = prev.hookRight(newNode);
|
||||||
|
col.size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headerNode.size = COLS;
|
||||||
|
|
||||||
|
return headerNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DancingLinks(boolean[][] cover) {
|
||||||
|
header = makeDLXBoard(cover);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runSolver() {
|
||||||
|
answer = new LinkedList<DancingNode>();
|
||||||
|
search(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleSolution(List<DancingNode> answer) {
|
||||||
|
int[][] result = parseBoard(answer);
|
||||||
|
printSolution(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = 9;
|
||||||
|
|
||||||
|
private int[][] parseBoard(List<DancingNode> answer) {
|
||||||
|
int[][] result = new int[size][size];
|
||||||
|
for (DancingNode n : answer) {
|
||||||
|
DancingNode rcNode = n;
|
||||||
|
int min = Integer.parseInt(rcNode.C.name);
|
||||||
|
for (DancingNode tmp = n.R; tmp != n; tmp = tmp.R) {
|
||||||
|
int val = Integer.parseInt(tmp.C.name);
|
||||||
|
if (val < min) {
|
||||||
|
min = val;
|
||||||
|
rcNode = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int ans1 = Integer.parseInt(rcNode.C.name);
|
||||||
|
int ans2 = Integer.parseInt(rcNode.R.C.name);
|
||||||
|
int r = ans1 / size;
|
||||||
|
int c = ans1 % size;
|
||||||
|
int num = (ans2 % size) + 1;
|
||||||
|
result[r][c] = num;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printSolution(int[][] result) {
|
||||||
|
int N = result.length;
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
String ret = "";
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
ret += result[i][j] + " ";
|
||||||
|
}
|
||||||
|
System.out.println(ret);
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package com.baeldung.algorithms.sudoku;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class DancingLinksAlgorithm {
|
||||||
|
private static int S = 9;
|
||||||
|
private static int SIDE = 3;
|
||||||
|
|
||||||
|
static char[][] board = {
|
||||||
|
{ '8', '.', '.', '.', '.', '.', '.', '.', '.' },
|
||||||
|
{ '.', '.', '3', '6', '.', '.', '.', '.', '.' },
|
||||||
|
{ '.', '7', '.', '.', '9', '.', '2', '.', '.' },
|
||||||
|
{ '.', '5', '.', '.', '.', '7', '.', '.', '.' },
|
||||||
|
{ '.', '.', '.', '.', '4', '5', '7', '.', '.' },
|
||||||
|
{ '.', '.', '.', '1', '.', '.', '.', '3', '.' },
|
||||||
|
{ '.', '.', '1', '.', '.', '.', '.', '6', '8' },
|
||||||
|
{ '.', '.', '8', '5', '.', '.', '.', '1', '.' },
|
||||||
|
{ '.', '9', '.', '.', '.', '.', '4', '.', '.' }
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
DancingLinksAlgorithm solver = new DancingLinksAlgorithm();
|
||||||
|
solver.solve(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean solve(char[][] board) {
|
||||||
|
boolean[][] cover = initializeExactCoverBoard(board);
|
||||||
|
DancingLinks dlx = new DancingLinks(cover);
|
||||||
|
dlx.runSolver();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndex(int row, int col, int num) {
|
||||||
|
return (row - 1) * S * S + (col - 1) * S + (num - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean[][] createExactCoverBoard() {
|
||||||
|
boolean[][] R = new boolean[9 * 9 * 9][9 * 9 * 4];
|
||||||
|
|
||||||
|
int hBase = 0;
|
||||||
|
|
||||||
|
for (int r = 1; r <= S; r++) {
|
||||||
|
for (int c = 1; c <= S; c++, hBase++) {
|
||||||
|
for (int n = 1; n <= S; n++) {
|
||||||
|
int index = getIndex(r, c, n);
|
||||||
|
R[index][hBase] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int r = 1; r <= S; r++) {
|
||||||
|
for (int n = 1; n <= S; n++, hBase++) {
|
||||||
|
for (int c1 = 1; c1 <= S; c1++) {
|
||||||
|
int index = getIndex(r, c1, n);
|
||||||
|
R[index][hBase] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c = 1; c <= S; c++) {
|
||||||
|
for (int n = 1; n <= S; n++, hBase++) {
|
||||||
|
for (int r1 = 1; r1 <= S; r1++) {
|
||||||
|
int index = getIndex(r1, c, n);
|
||||||
|
R[index][hBase] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int br = 1; br <= S; br += SIDE) {
|
||||||
|
for (int bc = 1; bc <= S; bc += SIDE) {
|
||||||
|
for (int n = 1; n <= S; n++, hBase++) {
|
||||||
|
for (int rDelta = 0; rDelta < SIDE; rDelta++) {
|
||||||
|
for (int cDelta = 0; cDelta < SIDE; cDelta++) {
|
||||||
|
int index = getIndex(br + rDelta, bc + cDelta, n);
|
||||||
|
R[index][hBase] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean[][] initializeExactCoverBoard(char[][] sudoku) {
|
||||||
|
boolean[][] R = createExactCoverBoard();
|
||||||
|
for (int i = 1; i <= S; i++) {
|
||||||
|
for (int j = 1; j <= S; j++) {
|
||||||
|
char n = sudoku[i - 1][j - 1];
|
||||||
|
if (n != '.') {
|
||||||
|
for (int num = 1; num <= S; num++) {
|
||||||
|
if ((char) ('0' + num) != n) {
|
||||||
|
Arrays.fill(R[getIndex(i, j, num)], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.baeldung.algorithms.sudoku;
|
||||||
|
|
||||||
|
class DancingNode {
|
||||||
|
DancingNode L, R, U, D;
|
||||||
|
ColumnNode C;
|
||||||
|
|
||||||
|
DancingNode hookDown(DancingNode n1) {
|
||||||
|
assert (this.C == n1.C);
|
||||||
|
n1.D = this.D;
|
||||||
|
n1.D.U = n1;
|
||||||
|
n1.U = this;
|
||||||
|
this.D = n1;
|
||||||
|
return n1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DancingNode hookRight(DancingNode n1) {
|
||||||
|
n1.R = this.R;
|
||||||
|
n1.R.L = n1;
|
||||||
|
n1.L = this;
|
||||||
|
this.R = n1;
|
||||||
|
return n1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlinkLR() {
|
||||||
|
this.L.R = this.R;
|
||||||
|
this.R.L = this.L;
|
||||||
|
}
|
||||||
|
|
||||||
|
void relinkLR() {
|
||||||
|
this.L.R = this.R.L = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlinkUD() {
|
||||||
|
this.U.D = this.D;
|
||||||
|
this.D.U = this.U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void relinkUD() {
|
||||||
|
this.U.D = this.D.U = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DancingNode() {
|
||||||
|
L = R = U = D = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DancingNode(ColumnNode c) {
|
||||||
|
this();
|
||||||
|
C = c;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user