Aritalab:Lecture/Programming/Java/AlgorithmX
From Metabolomics.JP
< Aritalab:Lecture | Programming | Java
D KnuthのアルゴリズムXのJava実装です。Sudoku用です。
import java.io.BufferedReader; import java.io.FileReader; import java.util.Iterator; import java.util.Stack; public class AlgorithmX { class Cell { Cell up, down, left, right; Header top; Object value = null; Cell() { } Cell(Object v) { value = v; left = right = this; } } class Header extends Cell { String label = null; int size = 0; Header(String l) { label = l; top = this; up = down = left = right = this; } } /** * @author Masanori Arita */ class ExactCoverMatrix { Header head = new Header(null); Stack<Cell> stack = new Stack<Cell>(); int colSize; /** * Matrix for Exact Cover (行が集合の数、列が要素の数)における列成分を定義する。 * * @param labels * label for columns */ void initializeHeaders(String[] labels) { colSize = labels.length; for (int i = 0; i < colSize; i) { String l = labels[i]; while (!h.label.equals(l)) { h = (Header) h.right; if (h == head) { System.err.println("No row of name: " + l); i; // 横のリンク if (first == null) first = last = tmp; else { last.right = tmp; tmp.left = last; last = tmp; } // 縦のリンク Cell above = h.up; above.down = h.up = tmp; tmp.up = above; tmp.down = h; } // 横のリンクを完成させる last.right = first; first.left = last; } /** * Brute forceで探索する部分 * * @param k * 探索の深さ。このプログラムでは使用せず。 */ void search(int k) { if (head.right == head) { printSudokuSolution(); return; } Header c = chooseColumn(); coverColumn(c); for (Cell r = c.down; r != c; r = r.down) { stack.push(r); for (Cell j = r.right; j != r; j = j.right) coverColumn(j.top); search(k + 1); stack.pop(); for (Cell j = r.left; j != r; j = j.left) uncoverColumn(j.top); } uncoverColumn(c.top); } void coverColumn(Header c) { colSize--; c.right.left = c.left; c.left.right = c.right; for (Cell i = c.down; i != c; i = i.down) for (Cell j = i.right; j != i; j = j.right) { j.down.up = j.up; j.up.down = j.down; j.top.size--; } } void uncoverColumn(Header c) { colSize; j.down.up = j; j.up.down = j; } c.right.left = c; c.left.right = c; } /** * マトリクス中で一番要素数の少ない列を返す * * @return */ Header chooseColumn() { Header maxCol = (Header) head.right; Header h = maxCol; for (int i = 1; i < colSize; i++) { h = (Header) h.right; if (h.size < maxCol.size) maxCol = h; } return maxCol; } void printSolution() { for (Iterator<Cell> i = stack.iterator(); i.hasNext();) { Cell c = i.next(); System.out.print(c.top.label + " "); for (Cell j = c.right; j != c; j = j.right) System.out.print(j.top.label + " "); System.out.println(); } } void printSudokuSolution() { int[][] answer = new int[9][9]; for (Iterator<Cell> I = stack.iterator(); I.hasNext();) { Cell c = I.next(); while (!c.top.label.startsWith("S")) c = c.right; int i = c.top.label.charAt(1) - '0' - 1; int j = c.top.label.charAt(2) - '0' - 1; int n = c.right.top.label.charAt(2) - '0'; answer[i][j] = n; } for (int i = 0; i < 9; i) System.out.print(answer[i][j] + " "); System.out.println(); } } } /* * 数独読み込みルーチン */ public int[][] readSudoku(String file) { // スペース区切りの9x9数を読み込んで9x9の二次元配列を返す int[][] sudoku = new int[9][9]; try { BufferedReader br = new BufferedReader(new FileReader(file)); String line; int row = 0; while (((line = br.readLine()) != null) && row < 9) { if (line.startsWith(";")) continue; String[] numbers = line.split(" "); for (int i = 0; i < 9; i; } } catch (Exception e) { e.printStackTrace(); } return sudoku; } void solveSudoku(int[][] sudoku) { String[] label = new String[] { "S", "C", "R", "B" }; String[] S = new String[9 * 9 * 4]; for (int i = 0; i < 4; i) for (int k = 0; k < 9; k++) S[i * 9 * 9 + j * 9 + k] = (label[i] + (j + 1)) + (k + 1); ExactCoverMatrix mat = new ExactCoverMatrix(); mat.initializeHeaders(S); for (int i = 0; i < 9; i) { if (sudoku[i][j] == 0) { for (int n = 1; n <= 9; n++) { mat.addRow(new String[] { ("S" + (i + 1) + (j + 1)), ("C" + (j + 1) + n), ("R" + (i + 1) + n), ("B" + ((i / 3) * 3 + (j / 3) + 1) + n) }, new Object[] { null, null, null, null }); } } else { int n = sudoku[i][j]; mat.addRow(new String[] { ("S" + (i + 1) + (j + 1)), ("C" + (j + 1) + n), ("R" + (i + 1) + n), ("B" + ((i / 3) * 3 + (j / 3) + 1) + n) }, new Object[] { null, null, null, null }); } } mat.search(0); } static public void main(String[] args) { AlgorithmX dl = new AlgorithmX(); int[][] sudoku = dl.readSudoku("c:/home/sudokuSample.txt"); dl.solveSudoku(sudoku); } }