SICP練習2.42~2.43です。Eight-queens 問題です。
問題
練習2.42:Eight-queens 問題。
練習2.43:Eight-queens 問題の時間コスト。
解答
練習2.42の解答
- import tango.util.container.LinkedList;
- import tango.math.Math;
- import tango.io.Stdout;
-
-
-
-
- LinkedList!(int[]) queens(int boardSize) {
- auto ls = new LinkedList!(int[]);
-
- void adjoinPosition(int[] pos, int col, int row) {
- int[] newPos = new int[col];
- if (pos !is null) {
- for (int i = 0; i < pos.length; i++) {
- newPos[i] = pos[i];
- }
- }
-
- newPos[col - 1] = row;
-
- ls.add(newPos);
- }
-
- bool safe(int[] pos, int col, int row) {
- if (col == 1) {
-
- return true;
- }
- int colDiv, rowDiv;
- int preRow;
- for (int i = 0; i < pos.length; i++) {
- preRow = pos[i];
- if (preRow == row) {
- return false;
- }
- colDiv = col - i - 1;
- rowDiv = abs(row - preRow);
- if (colDiv == rowDiv) {
- return false;
- }
- }
- return true;
- }
-
- LinkedList!(int[]) queenCols(int k) {
- if (k > boardSize) {
- return ls;
- }
-
- int prePos = ls.size();
-
-
- if (k == 1) {
- for (int i = 1; i <= boardSize; i++) {
- adjoinPosition(null, k, i);
- }
- }
-
- if (k > 1) {
- foreach (int[] pos ; ls) {
- for (int i = 1; i <= boardSize; i++) {
- if (safe(pos, k, i)) {
- adjoinPosition(pos, k, i);
- }
- }
- }
- }
-
-
- if (prePos > 0) {
- ls.removeRange(ls.size() - prePos, ls.size() - 1);
- }
-
- return queenCols(k + 1);
- }
-
- return queenCols(1);
- }
-
- void main() {
- int boardSize = 8;
- LinkedList!(int[]) qs = queens(boardSize);
- int count;
- foreach (int[] pos ; qs) {
- foreach (int r ; pos) {
- Stdout.format("{}\t", r);
- }
- count++;
- Stdout.newline();
- }
- Stdout.formatln("全ての解の数: {}", count);
- }
import tango.util.container.LinkedList; import tango.math.Math; import tango.io.Stdout; /** * SICP練習2.42。 */ LinkedList!(int[]) queens(int boardSize) { auto ls = new LinkedList!(int[]); void adjoinPosition(int[] pos, int col, int row) { int[] newPos = new int[col]; if (pos !is null) { for (int i = 0; i < pos.length; i++) { newPos[i] = pos[i]; } } newPos[col - 1] = row; // 先頭に追加 ls.add(newPos); } bool safe(int[] pos, int col, int row) { if (col == 1) { // first col, 常に safe return true; } int colDiv, rowDiv; int preRow; for (int i = 0; i < pos.length; i++) { preRow = pos[i]; if (preRow == row) { return false; } colDiv = col - i - 1; rowDiv = abs(row - preRow); if (colDiv == rowDiv) { return false; } } return true; } LinkedList!(int[]) queenCols(int k) { if (k > boardSize) { return ls; } int prePos = ls.size(); // 初回 if (k == 1) { for (int i = 1; i <= boardSize; i++) { adjoinPosition(null, k, i); } } if (k > 1) { foreach (int[] pos ; ls) { for (int i = 1; i <= boardSize; i++) { if (safe(pos, k, i)) { adjoinPosition(pos, k, i); } } } } // 前回の位置情報を削除 if (prePos > 0) { ls.removeRange(ls.size() - prePos, ls.size() - 1); } return queenCols(k + 1); } return queenCols(1); } void main() { int boardSize = 8; LinkedList!(int[]) qs = queens(boardSize); int count; foreach (int[] pos ; qs) { foreach (int r ; pos) { Stdout.format("{}\t", r); } count++; Stdout.newline(); } Stdout.formatln("全ての解の数: {}", count); }
import tango.util.container.LinkedList; import tango.math.Math; import tango.io.Stdout; /** * SICP練習2.42。 */ LinkedList!(int[]) queens(int boardSize) { auto ls = new LinkedList!(int[]); void adjoinPosition(int[] pos, int col, int row) { int[] newPos = new int[col]; if (pos !is null) { for (int i = 0; i < pos.length; i++) { newPos[i] = pos[i]; } } newPos[col - 1] = row; // 先頭に追加 ls.add(newPos); } bool safe(int[] pos, int col, int row) { if (col == 1) { // first col, 常に safe return true; } int colDiv, rowDiv; int preRow; for (int i = 0; i < pos.length; i++) { preRow = pos[i]; if (preRow == row) { return false; } colDiv = col - i - 1; rowDiv = abs(row - preRow); if (colDiv == rowDiv) { return false; } } return true; } LinkedList!(int[]) queenCols(int k) { if (k > boardSize) { return ls; } int prePos = ls.size(); // 初回 if (k == 1) { for (int i = 1; i <= boardSize; i++) { adjoinPosition(null, k, i); } } if (k > 1) { foreach (int[] pos ; ls) { for (int i = 1; i <= boardSize; i++) { if (safe(pos, k, i)) { adjoinPosition(pos, k, i); } } } } // 前回の位置情報を削除 if (prePos > 0) { ls.removeRange(ls.size() - prePos, ls.size() - 1); } return queenCols(k + 1); } return queenCols(1); } void main() { int boardSize = 8; LinkedList!(int[]) qs = queens(boardSize); int count; foreach (int[] pos ; qs) { foreach (int r ; pos) { Stdout.format("{}\t", r); } count++; Stdout.newline(); } Stdout.formatln("全ての解の数: {}", count); }
実行結果
c:\home\sicp>q2_42.exe
1 7 4 6 8 2 5 3
1 7 5 8 2 4 6 3
1 6 8 3 7 4 2 5
1 5 8 6 3 7 2 4
2 8 6 1 3 5 7 4
2 7 3 6 8 5 1 4
2 7 5 8 1 4 6 3
2 6 1 7 4 8 3 5
2 6 8 3 1 4 7 5
2 5 7 4 1 8 6 3
2 5 7 1 3 8 6 4
2 4 6 8 3 1 7 5
3 8 4 7 1 6 2 5
3 7 2 8 5 1 4 6
3 7 2 8 6 4 1 5
3 6 2 7 1 4 8 5
3 6 2 7 5 1 8 4
3 6 2 5 8 1 7 4
3 6 4 2 8 5 7 1
3 6 4 1 8 5 7 2
3 6 8 2 4 1 7 5
3 6 8 1 4 7 5 2
3 6 8 1 5 7 2 4
3 5 2 8 1 7 4 6
3 5 2 8 6 4 7 1
3 5 7 1 4 2 8 6
3 5 8 4 1 7 2 6
3 1 7 5 8 2 4 6
4 8 1 5 7 2 6 3
4 8 1 3 6 2 7 5
4 8 5 3 1 7 2 6
4 7 1 8 5 2 6 3
4 7 3 8 2 5 1 6
4 7 5 3 1 6 8 2
4 7 5 2 6 1 3 8
4 6 1 5 2 8 3 7
4 6 8 3 1 7 5 2
4 6 8 2 7 1 3 5
4 2 5 8 6 1 3 7
4 2 7 5 1 8 6 3
4 2 7 3 6 8 1 5
4 2 7 3 6 8 5 1
4 2 8 6 1 3 5 7
4 2 8 5 7 1 3 6
4 1 5 8 2 7 3 6
4 1 5 8 6 3 7 2
5 8 4 1 3 6 2 7
5 8 4 1 7 2 6 3
5 7 1 4 2 8 6 3
5 7 1 3 8 6 4 2
5 7 2 6 3 1 4 8
5 7 2 6 3 1 8 4
5 7 2 4 8 1 3 6
5 7 4 1 3 8 6 2
5 3 1 7 2 8 6 4
5 3 1 6 8 2 4 7
5 3 8 4 7 1 6 2
5 2 4 7 3 8 6 1
5 2 4 6 8 3 1 7
5 2 6 1 7 4 8 3
5 2 8 1 4 7 3 6
5 1 4 6 8 2 7 3
5 1 8 6 3 7 2 4
5 1 8 4 2 7 3 6
6 8 2 4 1 7 5 3
6 4 1 5 8 2 7 3
6 4 2 8 5 7 1 3
6 4 7 1 3 5 2 8
6 4 7 1 8 2 5 3
6 3 1 8 4 2 7 5
6 3 1 8 5 2 4 7
6 3 1 7 5 8 2 4
6 3 5 8 1 4 2 7
6 3 5 7 1 4 2 8
6 3 7 4 1 8 2 5
6 3 7 2 4 8 1 5
6 3 7 2 8 5 1 4
6 2 7 1 3 5 8 4
6 2 7 1 4 8 5 3
6 1 5 2 8 3 7 4
7 5 3 1 6 8 2 4
7 4 2 8 6 1 3 5
7 4 2 5 8 1 3 6
7 3 1 6 8 5 2 4
7 3 8 2 5 1 6 4
7 2 4 1 8 5 3 6
7 2 6 3 1 4 8 5
7 1 3 8 6 4 2 5
8 4 1 3 6 2 7 5
8 3 1 6 2 5 7 4
8 2 4 1 7 5 3 6
8 2 5 3 1 7 4 6
全ての解の数: 92 |
練習2.43の解答
Louisの実装は、上記ソースの60と61行を入れ替えることです。そうすると、既に処理済みの位置を繰り返しチェックしてしまいます。queen-cols(8)は1(8^0)回、queen-cols(7)は8(8^1)回・・・queen-cols(k)は8^(8-k)回呼び出されます。従って、Louisの実装では、queen-cols は合計で (8^0 + 8^1 + ... + 8^7 = 8^8 - 1) 回呼び出されます。その一方、元々の実装は 8^2 回です。結局、Louis の実装は約 (8^6) * T の時間が要します。
|