최소한의 단서 스도쿠 해석기를 구축


16

이 질문 을 진술하려고 시도 했지만 더 객관적인 해결 기준이 있습니다.

당신의 임무는 S당신이 선택한 형식으로 해결 된 스도쿠 그리드를 취하고 가능한 S고유 한 솔루션 만큼 가능한 단서가없는 문제 그리드를 생성 하는 프로그램이나 기능을 구축하는 것입니다. ( S솔루션이 유일무이 한 한 무차별 대입을 포함하여 고유 한 솔루션이 어떤 방법인지 는 중요하지 않습니다 .)


이 파일 에있는 100,000 개의 솔루션 그리드 세트 (7.82MB 다운로드)를 통해 프로그램을 실행하고 솔루션이 생성하는 100,000 개의 모든 문제 그리드에 실마리 수를 추가하여 프로그램의 점수를 매 깁니다.

위 테스트 파일의 Sudoku 솔루션은 왼쪽에서 오른쪽으로, 위에서 아래로 81 자 문자열로 표시됩니다. 테스트 파일의 입력을 사용 가능한 솔루션으로 전환하는 데 필요한 코드는 솔루션의 바이트 수에 포함되지 않습니다.

Flood Paint 챌린지에서와 같이 프로그램은 실제로 100,000 퍼즐을 모두 유효한 솔루션으로 간주하기 위해 유효한 출력을 생성해야합니다. 짧은 테스트 코드로 인해 10 만 건의 테스트 사례에서 가장 적은 총 단서를 출력하는 프로그램이 승자입니다.


현재 점수 판 :

  1. 2,361,024- 넛키, C
  2. 2,580,210 -es1024, PHP
  3. 6,000,000- 카펫 파이썬, 파이썬 2
  4. 7,200,000 -Joe Z., Python

또한 1,700,000 미만의 솔루션을 주장하는 솔루션이 가짜라는 것을 확신 할 수는 있지만 얼마나 낮은 솔루션인지는 알고 싶습니다.
Joe Z.

답변:


8

C-2,361,024 2,509,949 실마리

무차별 대입 솔버가 하나의 고유 한 솔루션 만 찾으면 마지막 셀에서 시작하는 단서를 제거합니다.

두 번째 시도 : 휴리스틱을 사용하여 마지막부터 시작하는 대신 단서를 제거하는 순서를 결정하십시오. 이렇게하면 코드가 훨씬 느리게 실행됩니다 (결과를 계산하기 위해 2 대신 20 분). 다른 휴리스틱을 실험하기 위해 솔버를 더 빠르게 만들 수는 있지만 지금은 그렇게 할 것입니다.

#include <stdio.h>
#include <string.h>
char ll[100];
short b[81];
char m[81];
char idx[81][24];
int s;
char lg[513];
void pri2() {
    int i;
    for(i=0;i<81;i++) putchar(lg[b[i]]);
    putchar('\n');
}
void solve(pos){
int i,p;
if (s > 1) return;
if (pos == 81) { s++; return; }
if (b[pos]) return solve(pos+1);
for (p=i=0;i<24;i++) p |= b[idx[pos][i]];
for (i = 0; i < 9; i++) if (!(p&(1<<i))) {
    b[pos] = 1 << i;
    solve(pos + 1);
}
b[pos] = 0;
}
int main() {
    int i,j,t;
    for(i=0;i<9;i++) lg[1<<i]='1'+i;
    lg[0] = '.';
    for(i=0;i<81;i++) {
    t = 0;
    for(j=0;j<9;j++) if(i/9*9 + j != i) idx[i][t++] = i/9*9 + j;
    for(j=0;j<9;j++) if(i%9 + j*9 != i) idx[i][t++] = i%9 + j*9;
    for(j=0;j<81;j++) if(j/27 == i/27 && i%9/3 == j%9/3 && i!=j) idx[i][t++] = j;
    }
    while(scanf("%s ",ll)>0) {
    memset(m, 0, sizeof(m));
    for(i=0;i<81;i++) b[i] = 1 << (ll[i]-'1');
    for(i=0;i<81;i++) {
    int j,k,l = 99;
    for(k=0;k<81;k++) if (m[k] <= l) l = m[k], j = k;
    m[j] = 24;
    t = b[j]; b[j] = 0;
    s = 0; solve(0);
    if (s > 1) b[j] = t;
    else for(k=0;k<24;k++) m[idx[j][k]]++;
    }
    pri2();
    }
    return 0;
}

1

파이썬 — 7,200,000 힌트

평소와 같이 다음은 마지막 참조 솔루션입니다.

def f(x): return x[:72] + "." * 9

각 열에 여전히 9 개 중 8 개의 숫자가 채워져 있고 맨 아래 열에있는 각 숫자는 단순히 열에 남은 9 번째 숫자이므로 숫자의 맨 아래 줄을 제거하면 퍼즐을 풀 수 있습니다.

심각한 경쟁자가 이보다 합법적으로 점수를 매길 수 있다면 나는 놀랄 것입니다.


내 말은, 당신은 마지막 것만 제거 할 수 있습니다.
seequ

당신은 또한 모든 것을 해결 한 채로 둘 수 있지만, 그 어느 것도 심각한 경쟁자가되지는 않을 것입니다.
Joe Z.

그렇다면 왜 이것이 심각한 경쟁자입니까?
theonlygusti

그렇지 않습니다. 그렇기 때문에 심각한 경쟁자가이 심각하지 않은 경쟁자보다 점수를 더 매기는 경우 놀라게 될 것이라고 말했습니다.
조 Z.

1

파이썬 2-6,000,000 단서

이 퍼즐을 해결하는 3 가지 일반적인 방법을 사용하는 간단한 솔루션 :

def f(x): 
    return ''.join('.' if i<9 or i%9==0 or (i+23)%27 in (0,3) else c 
        for i,c in enumerate(x))

이 함수는 다음과 같은 단서 형식을 생성합니다.

.........
.dddddddd
.dddddddd
.ddd.dd.d
.dddddddd
.dddddddd
.ddd.dd.d
.dddddddd
.dddddddd

이것은 항상 해결할 수 있습니다. 4 개의 3x3 부분이 먼저 해결 된 다음 8 열, 9 행이 해결됩니다.


1

PHP — 2,580,210 개의 단서

먼저 모든 상자의 마지막 행과 열 및 오른쪽 하단을 제거합니다. 그런 다음 각 셀을 지우고 각 변경 후 간단한 솔버를 통해 보드를 실행하여 보드를 여전히 확실하게 해결할 수 있도록합니다.

아래 코드의 대부분은 이전 답변 중 하나 에서 수정되었습니다 . printBoard빈 셀에는 0을 사용합니다.

<?php
// checks each row/col/block and removes impossible candidates
function reduce($cand){
    do{
        $old = $cand;
        for($r = 0; $r < 9; ++$r){
        for($c = 0; $c < 9; ++$c){
            if(count($cand[$r][$c]) == 1){ // if filled in
                // remove values from row and col and block
                $remove = $cand[$r][$c];
                for($i = 0; $i < 9; ++$i){
                    $cand[$r][$i] = array_diff($cand[$r][$i],$remove);
                    $cand[$i][$c] = array_diff($cand[$i][$c],$remove);
                    $br = floor($r/3)*3+$i/3;
                    $bc = floor($c/3)*3+$i%3;
                    $cand[$br][$bc] = array_diff($cand[$br][$bc],$remove);
                }
                $cand[$r][$c] = $remove;
            }
        }}
    }while($old != $cand);
    return $cand;
}

// checks candidate list for completion
function done($cand){
    for($r = 0; $r < 9; ++$r){
    for($c = 0; $c < 9; ++$c){
        if(count($cand[$r][$c]) != 1)
            return false;
    }}
    return true;
}

// board format: [[1,2,0,3,..],[..],..], $b[$row][$col]
function solve($board){
    $cand = [[],[],[],[],[],[],[],[],[]];
    for($r = 0; $r < 9; ++$r){
    for($c = 0; $c < 9; ++$c){
        if($board[$r][$c]){ // if filled in
            $cand[$r][$c] = [$board[$r][$c]];
        }else{
            $cand[$r][$c] = range(1, 9);
        }
    }}
    $cand = reduce($cand);

    if(done($cand))  // goto not really necessary
        goto end;    // but it feels good to use it 
    else return false;

    end:
    // back to board format
    $b = [];
    for($r = 0; $r < 9; ++$r){
        $b[$r] = [];
        for($c = 0; $c < 9; ++$c){
            if(count($cand[$r][$c]) == 1)
                $b[$r][$c] = array_pop($cand[$r][$c]);
            else 
                $b[$r][$c] = 0;
        }
    }
    return $b;
}

function add_zeros($board, $ind){
    for($r = 0; $r < 9; ++$r){
    for($c = 0; $c < 9; ++$c){
        $R = ($r + (int)($ind/9)) % 9;
        $C = ($c + (int)($ind%9)) % 9;
        if($board[$R][$C]){
            $tmp = $board[$R][$C];
            $board[$R][$C] = 0;
            if(!solve($board))
                $board[$R][$C] = $tmp;
        }   
    }}
    return $board;
}

function generate($board, $ind){
    // remove last row+col
    $board[8] = [0,0,0,0,0,0,0,0,0];
    foreach($board as &$j) $j[8] = 0;

    // remove bottom corner of each box
    $board[2][2] = $board[2][5] = $board[5][2] = $board[5][5] = 0;

    $board = add_zeros($board, $ind);

    return $board;    
}
function countClues($board){
    $str = implode(array_map('implode', $board));
    return 81 - substr_count($str, '0');
}

function generateBoard($board){
    return generate($board, 0);
}

function printBoard($board){
    for($i = 0; $i < 9; ++$i){
        echo implode(' ', $board[$i]) . PHP_EOL;
    }
    flush();
}
function readBoard($str){
    $tmp = str_split($str, 9);
    $board = [];
    for($i = 0; $i < 9; ++$i)
        $board[] = str_split($tmp[$i], 1);
    return $board;
}
// testing
$n = 0;
$f = fopen('ppcg_sudoku_testing.txt', 'r');
while(($l = fgets($f)) !== false){
    $board = readBoard(trim($l));
    $n += countClues(generateBoard($board));
}
echo $n;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.