BAEL-1298 Dancing Links Algorithm. Smaller changes to Backtracking

This commit is contained in:
iaforek 2017-12-03 19:48:43 +00:00
parent 3351d50a5a
commit cbf7bcbbbf
5 changed files with 336 additions and 15 deletions

View File

@ -2,23 +2,25 @@ package com.baeldung.algorithms.sudoku;
public class BacktrackingAlgorithm {
public static void main(String[] args) {
char[][] board = {
{ '8', '.', '.', '.', '.', '.', '.', '.', '.' },
{ '.', '.', '3', '6', '.', '.', '.', '.', '.' },
{ '.', '7', '.', '.', '9', '.', '2', '.', '.' },
static char[][] board = {
{ '8', '.', '.', '.', '.', '.', '.', '.', '.' },
{ '.', '.', '3', '6', '.', '.', '.', '.', '.' },
{ '.', '7', '.', '.', '9', '.', '2', '.', '.' },
{ '.', '5', '.', '.', '.', '7', '.', '.', '.' },
{ '.', '.', '.', '.', '4', '5', '7', '.', '.' },
{ '.', '.', '.', '1', '.', '.', '.', '3', '.' },
{ '.', '.', '1', '.', '.', '.', '.', '6', '8' },
{ '.', '.', '.', '.', '4', '5', '7', '.', '.' },
{ '.', '.', '.', '1', '.', '.', '.', '3', '.' },
{ '.', '.', '1', '.', '.', '.', '.', '6', '8' },
{ '.', '.', '8', '5', '.', '.', '.', '1', '.' },
{ '.', '9', '.', '.', '.', '.', '4', '.', '.' }
{ '.', '9', '.', '.', '.', '.', '4', '.', '.' }
};
public static void main(String[] args) {
BacktrackingAlgorithm solver = new BacktrackingAlgorithm();
solver.solve(board);
solver.printBoard();
}
public void printBoard() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
System.out.print(board[i][j] + " ");
@ -26,7 +28,7 @@ public class BacktrackingAlgorithm {
System.out.println();
}
}
public boolean solve(char[][] board) {
for (int r = 0; r < board.length; r++) {
for (int c = 0; c < board[0].length; c++) {
@ -45,7 +47,7 @@ public class BacktrackingAlgorithm {
}
return true;
}
public boolean isValid(char[][] board, int r, int c) {
boolean[] row = new boolean[9];
for (int i = 0; i < 9; i++) {
@ -68,7 +70,7 @@ public class BacktrackingAlgorithm {
}
}
}
boolean[] grid = new boolean[9];
for (int i = (r / 3) * 3; i < (r / 3) * 3 + 3; i++) {
for (int j = (c / 3) * 3; j < (c / 3) * 3 + 3; j++) {
@ -79,7 +81,7 @@ public class BacktrackingAlgorithm {
return false;
}
}
}
}
}
return true;
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}