Построить судоку как минимум подсказку

16

Моя попытка сформулировать этот вопрос , но с более объективным критерием решения.

Ваша задача состоит в том, чтобы создать программу или функцию, которая использует решенную сетку Судоку Sв выбранном вами формате и пытается создать сетку проблем с как можно меньшим количеством подсказок, которые имеют Sуникальное решение. (Неважно, какой метод Sявляется уникальным решением, включая грубую силу, если решение уникально доказуемо.)


Ваша программа будет оценена путем запуска ее через набор из 100 000 сеток решений, найденных в этом файле (загрузка 7,82 МБ), и суммирования количества подсказок во всех 100 000 сеток проблем, которые создает ваше решение.

Решения судоку в приведенном выше тестовом файле выражаются в виде строки из 81 символа слева направо, затем сверху вниз. Код, необходимый для преобразования входных данных в тестовом файле в пригодное для использования решение, не будет учитываться в счетчике байтов вашего решения.

Как и в моей задаче Flood Paint , ваша программа должна выдавать действительный вывод для всех 100 000 головоломок, чтобы считаться верным решением. Программа, которая выводит наименьшее общее количество подсказок для всех 100 000 тестовых случаев, является победителем, с более коротким кодом, разрывающим связь.


Текущее табло:

  1. 2,361,024 - нутки, C
  2. 2,580,210 - es1024, PHP
  3. 6 000 000 - CarpetPython, Python 2
  4. 7 200 000 - Джо З., Питон
Джо З.
источник
Кроме того, вы можете быть уверены, что любое решение, требующее менее 1 700 000 решений, является фальшивым, но я хочу посмотреть, насколько низкими они могут быть.
Джо З.

Ответы:

8

C - 2,361,024 2,509,949 подсказок

Удалите подсказки, начиная с последней ячейки, если решатель грубой силы находит только одно уникальное решение.

Вторая попытка: используйте эвристику, чтобы решить, в каком порядке удалять ключи, а не начинать с последней. Это заставляет код работать намного медленнее (20 минут вместо 2 для вычисления результата). Я мог бы сделать решатель быстрее, поэкспериментировать с другой эвристикой, но пока это подойдет.

#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;
}
nutki
источник
1

Python - 7 200 000 подсказок

Как обычно, вот последнее эталонное решение:

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

Удаление нижнего ряда чисел доказуемо оставляет головоломку разрешимой во всех случаях, так как в каждом столбце по-прежнему заполнено 8 из 9 чисел, а каждое число в нижнем ряду - просто девятое число, оставшееся в столбце.

Если любому серьезному сопернику удастся юридически забить хуже, чем этот, я буду удивлен.

Джо З.
источник
Я имею в виду, вы можете удалить только последний.
Seequ
Вы также можете просто оставить все решенным, но ни один из них не станет серьезным соперником.
Джо З.
Так почему же это серьезный соперник?
theonlygusti
Это не. Вот почему я сказал, что был бы удивлен, если бы серьезному сопернику удавалось забить хуже, чем этому несерьезному сопернику.
Джо З.
1

Python 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 части 3х3, затем 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;
es1024
источник