BAEL-1298 Dancing Links Algorithm. Smaller changes to Backtracking
This commit is contained in:
parent
3351d50a5a
commit
cbf7bcbbbf
@ -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;
|
||||
}
|
||||
|
@ -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