数独の問題数を数え上げる
Posted feedbacks - Java
288通りの最終盤面を取得し(Sudoku2x2#next())、 各マスの数字の有無の全パターン(2^16-2通り)について 問題が解けるかどうか(SudokuSolver2x2#solve())調べています。 要は総当たりです。 私の環境では、実行完了まで3分以上かかっています。 エレガントからはほど遠いコードですが 答えまで出る投稿が少ないので、参考までに。 $ time java Sudoku2x2 1 0 2 0 3 0 4 25728 5 284160 6 1041408 7 2141184 8 2961024 9 2958336 10 2204928 11 1239552 12 522624 13 161280 14 34560 15 4608 real 3m7.374s user 3m6.433s sys 0m0.334s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | import java.util.*;
public class Sudoku2x2 implements Iterator<int[]>, SudokuCommon2x2 {
private int count;
private final int maxCount;
private int[] nextValue;
public static void main(String[] args) {
countUpAll();
}
public static void countUpAll() {
Sudoku2x2 sudoku = new Sudoku2x2();
SudokuSolver2x2 solver = new SudokuSolver2x2();
int[] counter = new int[16];
int[] nums, nums2 = new int[16];
while (sudoku.hasNext()) {
nums = sudoku.next();
for (int i = 1; i < 0xffff; ++i) {
int n = 0;
Arrays.fill(nums2, 0);
for (int j = 0; j < 16; ++j) {
if(0<(i&(1<<j))) {
nums2[j] = nums[j];
++n;
}
}
if(solver.solve(nums2)) ++counter[n];
}
}
for (int i = 1; i <= 15; ++i) {
System.out.println(i + " " + counter[i]);
}
}
public Sudoku2x2() {
count = 0;
maxCount = (int) Math.pow(DIGITS_PATTERN.length, 4);
nextValue = new int[16];
generateNext();
}
public boolean hasNext() {
return nextValue!=null;
}
public int[] next() {
if(hasNext()) {
int[] returnValue = new int[16];
System.arraycopy(nextValue, 0, returnValue, 0, 16);
generateNext();
return returnValue;
}
throw new NoSuchElementException();
}
private void generateNext() {
do {
for (int c0 = count, i = 0; i < 4; ++i) {
System.arraycopy(DIGITS_PATTERN[c0%24], 0, nextValue, i*4, 4);
if(i==1) {
if(!containsAllNumbers(nextValue, BOX[0])) break;
if(!containsAllNumbers(nextValue, BOX[1])) break;
}
c0 = c0 / 24;
}
++count;
} while(
(
!containsAllNumbers(nextValue, BOX[2])
|| !containsAllNumbers(nextValue, BOX[3])
|| !containsAllNumbers(nextValue, COLUMN[0])
|| !containsAllNumbers(nextValue, COLUMN[1])
|| !containsAllNumbers(nextValue, COLUMN[2])
|| !containsAllNumbers(nextValue, COLUMN[3])
) && count < maxCount
);
if(maxCount <= count) nextValue = null;
}
private static boolean containsAllNumbers(int[] block, int[] index) {
int test = 0;
for(int i=0;i<index.length;++i) {
test |= 1<<(block[index[i]]-1);
}
return test==15;
}
public void remove() { throw new UnsupportedOperationException(); }
}
class SudokuSolver2x2 implements SudokuCommon2x2 {
SudokuCell[] grid;
SudokuCell[][] allBlocks;
int status;
SudokuSolver2x2() {
grid = new SudokuCell[16];
for(int i=0;i<grid.length;++i) grid[i] = new SudokuCell();
allBlocks = new SudokuCell[][] {
getBlock(BOX[0]),
getBlock(BOX[1]),
getBlock(BOX[2]),
getBlock(BOX[3]),
getBlock(COLUMN[0]),
getBlock(COLUMN[1]),
getBlock(COLUMN[2]),
getBlock(COLUMN[3]),
getBlock(ROW[0]),
getBlock(ROW[1]),
getBlock(ROW[2]),
getBlock(ROW[3])
};
}
public boolean solve(int[] nums) {
status = 0;
for(int i=0;i<grid.length;++i) {
grid[i].value = i<nums.length?nums[i]:0;
grid[i].possibleList = 0<grid[i].value?0:15;
}
while(true) {
solveInner();
switch(status) {
case -1: return false; // logical error
case 1: return true; // solved
}
}
}
protected void solveInner() {
boolean modified = false, solved = true;
int test = 0;
for(int i=0;i<allBlocks.length;++i) {
for(int j=0;j<allBlocks[i].length;++j) {
modified |= allBlocks[i][j].updatePossibleList(allBlocks[i]);
test |= 1<<(allBlocks[i][j].value-1);
}
solved &= (test==15);
}
if(!modified&&!solved) status = -1;
if(solved) status = 1;
}
protected SudokuCell[] getBlock(int[] indexes) {
SudokuCell[] returnValue = new SudokuCell[indexes.length];
for(int i=0;i<indexes.length;++i)
returnValue[i] = grid[indexes[i]];
return returnValue;
}
protected class SudokuCell {
int value;
int possibleList;
public boolean isPossible(int i) {
return 0<i && (0<(possibleList & 1<<(i-1)));
}
private void setValue(int i) {
value = i;
possibleList = 0;
}
public boolean updatePossibleList(SudokuCell[] sp) {
boolean updated = false;
for(int i=0;i<sp.length;++i) {
if(this==sp[i]) continue;
if(isPossible(sp[i].value)) {
possibleList &= ~(1<<(sp[i].value-1));
updated = true;
}
}
if(updated) check();
return updated;
}
public void check() {
if(value==0) {
switch(possibleList) {
case 1: setValue(1); break;
case 2: setValue(2); break;
case 4: setValue(3); break;
case 8: setValue(4); break;
}
}
}
}
}
interface SudokuCommon2x2 {
public static final int[][] COLUMN = {
{ 0, 4, 8, 12 }, { 1, 5, 9, 13 }, { 2, 6, 10, 14 }, { 3, 7, 11, 15 }
};
public static final int[][] ROW = {
{ 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 }
};
public static final int[][] BOX = {
{ 0, 1, 4, 5 }, { 2, 3, 6, 7 }, { 8, 9, 12, 13 }, { 10, 11, 14, 15 }
};
public static final int[][] DIGITS_PATTERN = {
{1, 2, 3, 4}, {1, 2, 4, 3}, {1, 3, 2, 4},
{1, 3, 4, 2}, {1, 4, 2, 3}, {1, 4, 3, 2},
{2, 1, 3, 4}, {2, 1, 4, 3}, {2, 3, 1, 4},
{2, 3, 4, 1}, {2, 4, 1, 3}, {2, 4, 3, 1},
{3, 1, 2, 4}, {3, 1, 4, 2}, {3, 2, 1, 4},
{3, 2, 4, 1}, {3, 4, 1, 2}, {3, 4, 2, 1},
{4, 1, 2, 3}, {4, 1, 3, 2}, {4, 2, 1, 3},
{4, 2, 3, 1}, {4, 3, 1, 2}, {4, 3, 2, 1}
};
}
|


ckbx #8115() Rating1/3=0.33
[ reply ]