Створіть мінімум поняття судоку нерозв'язки


16

Моя спроба викласти це питання , але з більш об'єктивним критерієм вирішення.

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


Ваша програма буде оцінена, виконавши її через набір 100000 сіток рішення, знайдених у цьому файлі (завантаження 7,82 Мб), і додавши кількість підказок у всіх 100 000 проблемних сітках, які виробляє ваше рішення.

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

Як і в моєму виклику фарби Flood Paint , ваша програма повинна насправді дати дійсний результат для всіх 100 000 головоломок, щоб вважати правильним рішенням. Програма, яка видає найменше загальних підказок для всіх 100 000 тестових випадків, є переможцем.


Поточний табло:

  1. 2,361,024 - нутки, С
  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;
}

1

Пітон - 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 - 2580 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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.