読者です 読者をやめる 読者になる 読者になる

世界一難しい数独がどれくらい難しいか解かせてみた

本当に解ける人いるの? フィンランド人数学者が作った “世界一難しい数独” が発表される | ロケットニュース24


フィンランド人数学者の Arto Inkala さんが今年も世界一難しい数独を発表していたので、CPANモジュール Games::Sudoku::Solver に解かせてみました。


一昨年発表のものはこちら


Inkalaさんが一昨年発表した問題

$ ./sudoku.pl sudoku_most_difficult2011.txt
sudoku_most_difficult2011.txt

===== Sudoku =====
 0 0 5 3 0 0 0 0 0
 8 0 0 0 0 0 0 2 0
 0 7 0 0 1 0 5 0 0
 4 0 0 0 0 5 3 0 0
 0 1 0 0 7 0 0 0 6
 0 0 3 2 0 0 0 8 0
 0 6 0 5 0 0 0 0 9
 0 0 4 0 0 0 0 3 0
 0 0 0 0 0 9 7 0 0

23 cells occupied, 58 cells free

--- solution 1 ---
(ひみつ)

[time] 1.0258446 (sec)

数時間集中して頑張ればなんとか解けるレベル。


今年の分

$ ./sudoku.pl sudoku_most_difficult2012.txt
sudoku_most_difficult2012.txt

===== Sudoku =====
 8 0 0 0 0 0 0 0 0
 0 0 3 6 0 0 0 0 0
 0 7 0 0 9 0 2 0 0
 0 5 0 0 0 7 0 0 0
 0 0 0 0 4 5 7 0 0
 0 0 0 1 0 0 0 3 0
 0 0 1 0 0 0 0 6 8
 0 0 8 5 0 0 0 1 0
 0 9 0 0 0 0 4 0 0

21 cells occupied, 60 cells free

--- solution 1 ---
(ひみつ)

[time] 27.8268216 (sec)


1 sec(2010) => 27.8 sec (2012)
自分でもざっとやってみましたが、一昨年のと違って初期値で確定できるところがありません。仮定値を置いて進めては出戻り、また別の場所に置いては出戻りでの繰り返しで、自宅や通勤電車のすきま時間ではとても無理。山にこもるしかないレベル。

完敗。

ソースコードはこちら

#!/usr/bin/perl

use strict;
use warnings;
use Games::Sudoku::Solver qw(:Minimal set_solution_max count_occupied_cells sudoku_read);
use Time::HiRes qw(gettimeofday tv_interval);

#引数チェック
my $argc = @ARGV;
if($argc < 1){ exit; }
my $sudoku_file =  $ARGV[0];
print $sudoku_file."\n";

my @sudoku;                                     # the Sudoku data structure
my @solution;                                   # the solution data structure

sudoku_read( \@sudoku, $sudoku_file );           # convert raw to internal representation

print "\n===== Sudoku =====\n";
sudoku_print( \@sudoku );                       # print the Sudoku


my  $cells_occupied = count_occupied_cells( \@sudoku ); # some statistics
print "\n", $cells_occupied, " cells occupied, ",
         81-$cells_occupied, " cells free\n";

set_solution_max(4);                            # stop having 4 solutions found

my $solutions;
#計測開始
my $t0 = [gettimeofday];

#5回測った平均値を出力する
for(my $i=0; $i<5; $i++){
  $solutions = sudoku_solve( \@sudoku, \@solution);    # solve the Sudoku
}

#計測終了(sec)
my $elasped = tv_interval($t0) / 5;     # 平均値(5)

#解が複数ある場合はすべてを出力
foreach my $n ( 1..$solutions ) {               # print the solutions
    print "\n--- solution $n ---\n";
    sudoku_print( $solution[$n-1] );
}
print "[time] $elasped (sec)\n";