Minimum ipucu veren bir Sudoku çözücü oluşturun


16

Bu soruyu belirtme girişimim , ancak daha objektif bir çözüm ölçütüyle.

Göreviniz S, seçtiğiniz bir formatta çözülmüş bir Sudoku ızgarası alan Sve benzersiz çözümü olan mümkün olduğunca az ipucu içeren bir sorun ızgarası oluşturmaya çalışan bir program veya işlev oluşturmaktır . ( SÇözümün benzersiz olduğu sürece kaba kuvvet de dahil olmak üzere hangi yöntemin benzersiz çözüm olduğu önemli değildir .)


Programınız, bu dosyada bulunan 100.000 çözüm ızgarası kümesini çalıştırarak (7.82 MB indirme) ve çözümünüzün ürettiği tüm 100.000 sorun ızgarasında ipucu sayısını toplayarak puanlanacaktır .

Yukarıdaki test dosyasındaki Sudoku çözümleri, soldan sağa ve sonra yukarıdan aşağıya 81 karakterlik bir dize olarak ifade edilir. Test dosyasındaki girdiyi kullanılabilir bir çözüme dönüştürmek için gereken kod, çözümünüzün bayt sayısına dahil edilmez.

Flood Paint meydan okumamda olduğu gibi , programınızın aslında 100.000 bulmacanın geçerli bir çözüm olması için geçerli bir çıktı üretmesi gerekir. Tüm 100.000 test vakası için en az toplam ipucu veren program kazanır ve daha kısa kod bir kravat kırır.


Mevcut skorbord:

  1. 2.361.024 - nutki, C
  2. 2.580.210 - es1024, PHP
  3. 6.000.000 - HalıPython, Python 2
  4. 7.200.000 - Joe Z., Python

Ayrıca, 1.700.000'den az çözüm olduğunu iddia eden herhangi bir çözümün sahte olduğundan emin olabilirsiniz, ancak bunların ne kadar düşük olabileceğini görmek istiyorum.
Joe

Yanıtlar:


8

C - 2.361.024 2.509.949 ipucu

Bir kaba kuvvet çözücü sadece bir benzersiz çözüm bulursa, son hücreden başlayan ipuçlarını kaldırın.

İkinci deneme: ipuçlarını sondan başlamak yerine hangi sırayla kaldıracağına karar vermek için buluşsal yöntem kullanın. Bu, kodun çok daha yavaş çalışmasını sağlar (sonucu hesaplamak için 2 yerine 20 dakika). Çözücüyü farklı buluşsal yöntemlerle denemek için daha hızlı yapabilirdim, ama şimdilik yapacak.

#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

Python - 7.200.000 ipucu

Her zamanki gibi, burada bir son yer referans çözümü:

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

Her bir sütunda hala 9 sayıdan 8'inin doldurulduğu ve alt satırdaki her sayı sütunda kalan dokuzuncu sayı olduğu için, sayıların alt sırasının kaldırılması bulmacayı her durumda çözülebilir hale getirir.

Herhangi bir ciddi yarışmacı yasal olarak bundan daha kötü skor yapmayı başarırsa, hayretler içinde kalacağım.


Yani, sadece sonuncuyu kaldırabilirsiniz.
seequ

Ayrıca her şeyi çözülmüş olarak bırakabilirsiniz, ancak bunların hiçbiri ciddi bir rakip olmayacaktır.
Joe

Peki bu neden ciddi bir yarışmacı?
theonlygusti

Değil. Bu yüzden ciddi bir yarışmacı bu ciddi olmayan yarışmacıdan daha kötü puan almayı başarırsa şaşkına döneceğim dedim.
Joe

1

Python 2 - 6.000.000 ipucu

Bu bulmacaları çözmek için 3 yaygın yöntemi kullanan basit bir çözüm:

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))

Bu işlev aşağıdaki gibi ipucu formatları üretir:

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

Bu her zaman çözülebilir. Önce 4 3x3 parça, sonra 8 sütun, sonra 9 satır çözülür.


1

PHP - 2.580.210 ipucu

Bu, ilk önce her satırın son satırını ve sütununu ve sağ alt köşesini kaldırır. Daha sonra, her hücrenin temizlenmesine çalışır ve her değişiklikten sonra tahtanın hala açık bir şekilde çözülebilir olmasını sağlamak için tahtayı basit bir çözücüden geçirir.

Aşağıdaki kodun çoğu eski yanıtlarımdan birinden değiştirildi . printBoardboş hücreler için 0 saniye kullanır.

<?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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.