Kaç tane Sudoku bulmacası var?


10

Bu bir Sudoku çözücü veya Sudoku denetleyicisi değildir.

Zorluğunuz, bir 2D Sudoku bulmacasının "blok" boyutunu ( klasik 9x9 kartı için 3 , 16x16 kartı için 4 , vb.) Girdi olarak verilen bir işlev veya komut dosyası yazmaktır . bu boyut için var olan farklı bulmacalar (çözümler).

Örneğin, girdi 3 verildiğinde, programınız, bilinen 9x9 Sudoku bulmacasının bilinen sayısı olan 6.670.903.752.021.072.936.960 numaralı bir kesime, istenen hassasiyette bir yaklaşık yazdırmalıdır. , çeşitli simetrileri dikkate alırken veya 5.472.730.538 . Çözümünüz simetrilerin sayılıp sayılmadığını veya yok sayıldığını belirtmelidir.

"İstenen hassasiyet" tanımlanmamış olarak bırakılır: programınız belirli bir süre çalışıp ardından çıktısını verebilir veya belirli sayıda önemli basamağa kadar hesaplayabilir, hatta sonsuza kadar çalışarak daha iyi ve daha iyi tahminler basabilir. Mesele şu ki, sonucu gerekli bir hassasiyetle sonlu bir zamanda hesaplamak mümkün olmalıdır. (Dolayısıyla "42" kabul edilebilir bir cevap değildir.) Sonuçlarınızın hassasiyetini mevcut makine şamandıraları ile sınırlamak kabul edilebilir.

Çevrimiçi kaynaklara erişme, kaynak kodunu dosya adına kaydetme vb. Yok.


Not: Bunun Zor bir Sorun olduğunu biliyorum (yanılmıyorsam NP-tamamlandı.) Ama bu soru sadece yaklaşık, istatistiksel bir çözüm istiyor. Örneğin, bir (veya daha iyi iki) kısıtlamayı karşılayan rastgele yapılandırmaları deneyebilir, bunlardan kaç tanesinin var olduğunu hesaplayabilir ve daha sonra üç kısıtlamanın tümünü karşılayan bir bulmacayı ne sıklıkla aldığınızı kontrol edebilirsiniz. Bu, küçük boyutlar (kesinlikle boyut = 3 ve muhtemelen 4 için) için uygun bir zamanda çalışacaktır, ancak algoritma herhangi bir boyut için çalışacak kadar genel olmalıdır.

En iyi algoritma kazanır.


PS2: Sorunun zorluğunu daha iyi yansıtmak ve daha akıllı çözümleri teşvik etmek için kod golfünden kod meydan okumasına geçtim. Ama görünüşe göre "en iyi algoritma" belirsiz olduğu için, onu doğru şekilde tanımlamaya çalışayım.

Yeterli zaman verildiğinde ve sabit faktörler (CPU ve yorumlayıcı hızı dahil) göz ardı edilirse veya asimtotik davranışları göz önünde bulundurularak, hangi çözüm en hızlı sonuca en hızlı şekilde dönüşür?


11
Bu gerçekten zor bir sorun değil mi? Sadece {1, 1, 288, 6e21} sayılarını üretmek için bir fonksiyon üretmenin en kısa yolunu mu yoksa bunu bir şekilde n> 3'e mi genişletmeyi istiyorsunuz?
algoritmalar

Kesin çözüm inanılmaz derecede zor bir sorundur, ancak bazı rastgele örnekleme ve birkaç saniye modern CPU zamanı ile bir yaklaşım hesaplanabilir. Elbette daha akıllı çözümler bekliyoruz!
Tobia

2
@ Tobia bu yaklaşım, kociemba.org/cube.htm'yi çözmek için N hamlesi gerektiren rubik küp pozisyonlarının yaklaşık sayısını bulmak için kullanıldı, böylece bu şekilde bir yaklaşım elde etmek mümkündür. Ancak, her satırı çözen bir program yazıp sütun ve karelerin çözülüp çözülmediğini görmek için testler yaparsam, bruteforce için (9!) ^ .) İsabet başına ortalama 1.6E28 deneme gerekir. Bu oldukça yavaş. Şimdi, hem satırların hem de sütunların doğru olduğundan ve sadece kareleri kontrol edebilsem, bir yere gidebilirdim. Ah! Bir fikrim var ...
Level River St

@steveverrill Gördün mü? :-)
Tobia

Analitik bir çözüm yok mu?
Newbrict

Yanıtlar:


3

C ++

Burada sunacağım şey, 3x3'lük bir durum için bir örnekle gösterilen bir algoritma. Teorik olarak NxN davasına genişletilebilir, ancak bunun çok daha güçlü bir bilgisayar ve / veya bazı ustaca ayarlamalar yapması gerekir. Ben ilerlerken bazı gelişmelerden bahsedeceğim.

Daha ileri gitmeden önce , Sudoku ızgarasının simetrilerini, yani başka bir ızgaraya giden dönüşümleri önemsiz bir şekilde not edelim . Blok boyutu 3 için simetriler aşağıdaki gibidir:

Yatay simetri

**The N=3 sudoku is said to consist of 3 "bands" of 3 "rows" each**
permute the three bands: 3! permutations = 6
permute the rows in each band: 3 bands, 3! permutations each =(3!)^3=216

Dikey simetri

**The N=3 sudoku is said to consist of 3 "stacks" of 3 "columns" each.**
the count is the same as for horizontal.

Izgaranın yatay ve dikey yansımalarının bunların bir kombinasyonu ile elde edilebileceğini unutmayın, bu yüzden sayılmaları gerekmez. Dikkate alınması gereken bir faktör olan bir başka uzaysal simetri daha vardır 2. Bu, toplam uzamsal simetriyi verir.

2*(N!*(N!)^N)^2 = 2*(6*216)^2=3359232 spatial symmetries for the case N=3.

Sonra yeniden etiketleme adı verilen çok önemli bir simetri daha var.

Relabelling gives a further (N^2)!=9!=362880 symmetries for the case N=3. So the total 
number of symmetries is 362880*3359232=1218998108160.

Toplam çözüm sayısı, simetriye özgü çözümlerin sayısının bu sayı ile çarpılmasıyla bulunamaz, çünkü bir dizi (% 1'den daha az) otomorfik çözüm vardır. Bu, bu özel çözümler için, bunları kendileriyle eşleştiren bir simetri işlemi veya bunları aynı diğer çözümle eşleştiren çoklu simetri işlemleri olduğu anlamına gelir.

Çözüm sayısını tahmin etmek için, soruna 4 adımda yaklaşıyorum:

1. r[362880][12]0 ile 8 arasındaki tüm olası permütasyonları içeren bir diziyi doldurun (bu programlama ve C cinsindendir, bu yüzden 1'den 9'a kadar kullanmayacağız.) Eğer zekiyseniz ikinci abonenin Bunun nedeni, bunu yaparken bir "satır" olarak değerlendireceğimizi akılda tutarak, r[9,10,11] == 1<<a | 1<<b | 1<<c9,10,11'in birinci, ikinci ve üçüncü yığına atıfta bulunduğu üç tamsayı da hesapladığımız için. ve a, b, c, bu satır için her yığınta bulunan üç sayıdır.

2. Bir diziyi b3 sıralı bir bandın tüm olası çözümleriyle doldurun . Bunu oldukça küçük tutmak için, yalnızca üst sıranın 012.345.678 olduğu çözümleri ekleyin. Bunu kaba kuvvetle, tüm olası orta sıraları üreterek r[0][10,11,12]ver[i][10,11,12] . Herhangi bir pozitif değer, aynı karede iki özdeş sayı olduğu ve bandın geçersiz olduğu anlamına gelir. İlk iki satır için geçerli bir kombinasyon olduğunda, 3. (alt) satırı aynı teknikle ararım.

Diziyi b [2000000] [9] olarak boyutlandırdım, ancak program yalnızca 1306368 çözüm buluyor. Kaç tane olduğunu bilmiyordum, bu yüzden dizi boyutunu böyle bıraktım. Bu aslında tek bir bant için olası çözümlerin sadece yarısıdır (wikipedia'da doğrulanmıştır), çünkü mevcut değerden sadece 3. satırı iyukarı doğru tararım. Çözeltilerin geri kalan yarısı, 2. ve 3. sıralar değiştirilerek önemsiz olarak bulunabilir.

Bilgilerin dizide saklanma şekli bilk başta biraz kafa karıştırıcıdır. 0..8verilen bir konumda bulunan sayıları saklamak için her bir tamsayıyı kullanmak yerine , burada her bir tamsayı sayılardan birini dikkate alır 0..8ve hangi sütunlarda bulunabileceğini belirtir. böylece b[x][7]==100100001x çözümünün 7 sayısının 0,5 ve 8 sütunlarında (sağdan sola) bulunduğunu gösterecektir. Bu gösterimin nedeni, bandın diğer olanaklarını yeniden etiketleyerek üretmemiz gerektiğidir ve bu temsil bunu yapmayı kolaylaştırır.

Yukarıdaki iki adım kurulumu içerir ve yaklaşık bir dakika sürer (gereksiz veri çıkışını kaldırırsam daha az olur. Aşağıdaki iki adım gerçek aramadır.)

3 Çatışmayan (yani belirli bir sütunda iki kez aynı sayıya sahip olmayan) ilk iki bandın çözümlerini rasgele arayın. Her zaman permütasyon 0 olduğunu varsayarak bant 1 için rastgele bir çözüm ve Rastgele bir permütasyon.Normalde 9999 denemeden daha az bir sonuç bulunur (binlerce aralıktaki ilk aşama vuruş oranı) ve bir saniyenin bir kısmını alır. Permütasyon ile, ikinci bant için b [] [] burada ilk satır her zaman 012,345,678'dir ve ilk satırdaki olası herhangi bir sayı dizisi mümkün olacak şekilde yeniden etiketleyin.

4 3. adımda bir isabet bulunduğunda, diğer ikiyle çakışmayan üçüncü bant için bir çözüm arayın. Sadece bir deneme yapmak istemiyoruz, aksi takdirde 3. adım için işlem süresi boşa gider. Öte yandan, buna çok fazla çaba sarf etmek istemiyoruz.

Sadece eğlenmek için, dün gece bunu en aptalca şekilde yaptım, ama yine de ilginçti (çünkü çağlar için hiçbir şey yoktu, sonra patlamalarda çok sayıda çözüm buldu.) Küçük bir hack ile bile bir veri noktası elde etmek bütün gece sürdü. (!z)Bunun kgeçerli bir çözüm olmadığını bildiğimiz anda son döngüyü iptal ettim (neredeyse 9 kat daha hızlı çalışmasını sağlar.) Tüm 1306368 kanonik çözümlerin 362880 yeniden etiketlemesini aradıktan sonra tüm ızgara için 1186585 çözüm buldu. blok, toplam 474054819840 olasılık. Bu, ikinci aşama için 400000'de 1'lik bir isabet oranı. Bir tarama yerine rastgele bir arama ile tekrar deneyeceğim. Birkaç milyon denemede makul bir cevap vermeli ve bu sadece birkaç saniye sürmelidir.

Genel cevap (362880 * (1306368 * 2)) ^ 3 * isabet oranı = 8,5E35 * isabet oranı olmalıdır. Sorudaki sayıdan geri hesaplayarak, 1 / 1.2E14'lük bir isabet oranı bekliyorum. Şimdiye kadar tek veri noktamda elde ettiğim şey 1 / (400000 * 1000), ki bu yaklaşık bir milyon faktör. Bu bir şans anomalisi, programımdaki bir hata veya matematiğimdeki bir hata olabilir. Birkaç test daha yapana kadar hangisi olduğunu bilmiyorum.

Bunu bu gece burada bırakacağım. Metin biraz cılız, yakında toplayacağım ve umarım daha fazla sonuç ekleyeceğim ve belki daha hızlı hale getirme ve kavramın N = 4'e nasıl genişletileceği hakkında birkaç kelime ekleyeceğim. Programımda çok daha fazla değişiklik yapacağımı sanmıyorum :-)

Ah .. program:

#include "stdafx.h"
#define _CRT_RAND_S
#include <algorithm>  
#include <time.h>

unsigned int n[] = { 0,1,2,3,4,5,6,7,8 }, r[362880][12], b[2000000][9],i,j,k,l,u,v,w,x,y,z;

int main () {

  //Run through all possible permutations of n[] and load them into r[][] 
  i=0;  
  do {
      r[i][9] = r[i][10] = r[i][11]=0;
      for (l = 0; l < 9; l++){
          r[i][l] = n[l];
          r[i][9 + l / 3] |= 1 << n[l];
      }
      if((i+1)%5040==0) printf("%d%d%d %d%d%d %d%d%d %o %o %o %o \n"
          ,r[i][0],r[i][1],r[i][2],r[i][3],r[i][4],r[i][5],r[i][6],r[i][7],r[i][8],r[i][9],r[i][10],r[i][11],r[i][9]+r[i][10]+r[i][11]);
      i++;
  } while ( std::next_permutation(n,n+9) );

  //Initialise b[][]
  for (l = 0; l<2000000; l++) for (k = 0; k<9; k++) b[l][k]=0;
  //fill b[][] with all solutions of the first band, where row0 ={0,1,2,3,4,5,6,7,8} and row1<row2 
  l=0;
  for (i = 0; i<362880; i++) 
  if (!(r[0][9] & r[i][9] | r[0][10] & r[i][10] | r[0][11] & r[i][11])){printf("%d %d \n",i,l);
     for (j=i; j<362880;j++) 
       if(!(r[0][9]&r[j][9] | r[0][10]&r[j][10] | r[0][11]&r[j][11] | r[j][9]&r[i][9] | r[j][10]&r[i][10] | r[j][11]&r[i][11] )){
           for (k = 0; k < 9; k++){
               b[l][r[0][k]]|=1<<k;
               b[l][r[i][k]]|=1<<k;
               b[l][r[j][k]]|=1<<k;
            } 
            l++;
       }
//        printf("%d%d%d %d%d%d %d%d%d %o %o %o %o \n"
//        ,r[i][0],r[i][1],r[i][2],r[i][3],r[i][4],r[i][5],r[i][6],r[i][7],r[i][8],r[i][9],r[i][10],r[i][11],r[i][9]+r[i][10]+r[i][11]);
//        printf("%d%d%d %d%d%d %d%d%d %o %o %o %o \n"
//        ,r[j][0],r[j][1],r[j][2],r[j][3],r[j][4],r[j][5],r[j][6],r[j][7],r[j][8],r[j][9],r[j][10],r[j][11],r[j][9]+r[j][10]+r[j][11]);
//        printf("%d %d %o %o %o %o %o %o %o %o %o \n",i,l,b[l][0],b[l][1],b[l][2],b[l][3],b[l][4],b[l][5],b[l][6],b[l][7],b[l][8]);
  }

  // find a random solution for the first 2 bands
  l=0;
  do{
      rand_s(&u); u /= INT_MIN / -653184; //1st band selection
      rand_s(&v); v /= INT_MIN / -181440; //2nd band permutation
      rand_s(&w); w /= INT_MIN / -653184; //2nd band selection
      z = 0;
      for (k = 0; k < 9; k++) z |= b[u][k] & b[w][r[v][k]];
      l++;
  } while (z);
  printf("finished random after %d tries \n",l);
  printf("found solution with top band %d permutation 0, and middle band %d permutation %d \n",u,w,v);
  getchar();

  // scan all possibilities for the last band
  l=0;
  for (i = 0; i < 362880; i++) for (j = 0; j < 1306368; j++){
              z=0;
              for(k=0;(k<9)&&(!z);k++) z|= b[u][k] & b[j][r[i][k]] | b[j][r[i][k]] & b[w][r[v][k]];
              if (!z){ l++; printf("solution %d : i= %d j=%d",l,i,j); }
  }
  printf("finished bottom band scan at %d millisec \n", clock()); getchar();
}
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.