Aritalab:Lecture/Programming/Java/AlgorithmX

From Metabolomics.JP
< Aritalab:Lecture | Programming | Java(Difference between revisions)
Jump to: navigation, search
 
 
Line 1: Line 1:
#REDIRECT [[Aritalab:Lecture/Algorithm/Sudoku]]
+
D KnuthのアルゴリズムXのJava実装です。Sudoku用です。
 +
 
 +
<pre>
 +
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++) {
 +
Header h = new Header(labels[i]);
 +
h.right = head;
 +
h.left = head.left;
 +
head.left.right = h;
 +
head.left = h;
 +
}
 +
}
 +
 
 +
/**
 +
* 文字配列を受け取り、該当する列にセルを作成する。 受け取る配列はinitializeHeadersと同じ順序とする。
 +
*
 +
* @param labels
 +
*            文字配列
 +
* @param values
 +
*            相当するセルの値
 +
*/
 +
void addRow(String[] labels, Object[] values) {
 +
Cell first = null, last = null;
 +
Header h = (Header) head.right;
 +
for (int i = 0; i < labels.length; 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++;
 +
break;
 +
}
 +
}
 +
// セルを挿入
 +
Cell tmp = new Cell(values[i]);
 +
tmp.top = h;
 +
h.size++;
 +
// 横のリンク
 +
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++;
 +
for (Cell i = c.up; i != c; i = i.up)
 +
for (Cell j = i.left; j != i; j = j.left) {
 +
j.top.size++;
 +
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++) {
 +
for (int j = 0; j < 9; j++)
 +
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++)
 +
sudoku[row][i] = Integer.parseInt(numbers[i]);
 +
row++;
 +
}
 +
} 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 j = 0; j < 9; j++)
 +
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++)
 +
for (int j = 0; j < 9; j++) {
 +
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);
 +
}
 +
}
 +
</pre>

Latest revision as of 14:49, 22 August 2017

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);
	}
}
Personal tools
Namespaces

Variants
Actions
Navigation
metabolites
Toolbox