कितने सुडोकू पहेली मौजूद हैं?


10

यह न तो सुडोकू सॉल्वर है, न ही सुडोकू चेकर।

आपकी चुनौती एक फ़ंक्शन या स्क्रिप्ट लिखने की है, जिसे एक 2 डी सुडोकू पहेली के "ब्लॉक" आकार के रूप में दिया गया है (जो कि क्लासिक 9x9 बोर्ड के लिए 3 है , 16x16 बोर्ड के लिए 4 , आदि) संख्या के एक अनुमान की गणना करेगा। अलग-अलग पहेलियां (समाधान) जो उस आकार के लिए मौजूद हैं।

उदाहरण के लिए, दिए गए इनपुट 3, आपके प्रोग्राम को एक सन्निकटन प्रिंट करना चाहिए, वांछित परिशुद्धता के लिए, संख्या 6,670,903,752,021,072,936,960 पर जो विभिन्न 9x9 सुडोकू पहेलियाँ , या 5,473,730,538 की विशिष्ट संख्या को जानते हैं जब विभिन्न समरूपताओं को ध्यान में रखते हैं। आपके समाधान में यह बताया जाना चाहिए कि क्या समरूपता को गिना या अनदेखा किया गया है।

"वांछित सटीकता" को अपरिभाषित छोड़ दिया जाता है: आपका कार्यक्रम किसी दिए गए समय के लिए चल सकता है और फिर इसका परिणाम आउटपुट कर सकता है, या इसे दिए गए महत्वपूर्ण अंकों की संख्या तक गणना कर सकता है, या हमेशा के लिए चला सकता है, बेहतर और बेहतर सन्निकटन मुद्रित कर सकता है। मुद्दा यह है कि यह किसी भी आवश्यक परिशुद्धता के लिए परिणाम की गणना करने के लिए संभव है, एक सीमित समय में। (तो "42" एक स्वीकार्य उत्तर नहीं है।) उपलब्ध मशीन फ़्लोट्स के लिए आपके परिणाम की शुद्धता को प्रतिबंधित करना स्वीकार्य है।

ऑनलाइन संसाधनों तक पहुंच नहीं, फ़ाइल नाम आदि में स्रोत कोड को संग्रहीत नहीं करना।


पुनश्च: मुझे पता है कि यह एक कठिन समस्या है (यदि मैं गलत नहीं हूं तो एनपी-पूर्ण।) लेकिन यह सवाल केवल अनुमानित, सांख्यिकीय समाधान के लिए पूछ रहा है। उदाहरण के लिए, आप यादृच्छिक विन्यास की कोशिश कर सकते हैं जो एक (या बेहतर दो) बाधाओं को संतुष्ट करते हैं, गणना करें कि उनमें से कितने मौजूद हैं और फिर जांचें कि आपको कितनी बार एक पहेली मिलती है जो सभी तीन बाधाओं को संतुष्ट करती है। यह छोटे आकार के लिए एक सभ्य समय में काम करेगा (निश्चित रूप से आकार = 3 और संभवतः 4 के लिए) लेकिन एल्गोरिथ्म किसी भी आकार के लिए काम करने के लिए पर्याप्त सामान्य होना चाहिए।

सबसे अच्छा एल्गोरिथ्म जीतता है।


PS2: मैं कोड-गोल्फ से कोड-चैलेंज में बदल गया ताकि समस्या की कठिनाई को बेहतर ढंग से प्रतिबिंबित किया जा सके और गूंगे लेकिन अच्छी तरह से गोल्फ वाले लोगों को बेहतर समाधान के लिए प्रोत्साहित किया जा सके। लेकिन चूंकि जाहिरा तौर पर "सर्वश्रेष्ठ एल्गोरिथ्म" अस्पष्ट है, इसलिए मुझे इसे ठीक से परिभाषित करने की कोशिश करें।

पर्याप्त समय और निरंतर कारकों (सीपीयू और इंट्रिप्टर गति सहित), या समकक्ष को देखते हुए, उनके विषम व्यवहार को देखते हुए, कौन सा समाधान सबसे तेजी से सटीक परिणाम में परिवर्तित होगा?


11
नहीं यह वास्तव में एक है वास्तव में कठिन समस्या ? क्या आप केवल {1, 1, 288, 6e21} संख्याओं का उत्पादन करने के लिए फ़ंक्शन का सबसे छोटा तरीका पूछ रहे हैं, या इसे किसी भी तरह n> 3 तक बढ़ा सकते हैं?
एल्गोरिथमशार्क

सटीक समाधान एक अविश्वसनीय रूप से कठिन समस्या है, लेकिन कुछ यादृच्छिक नमूने और आधुनिक सीपीयू समय के कुछ सेकंड के साथ एक अनुमान की गणना की जा सकती है। बेशक होशियार समाधान का स्वागत है!
तोबिया

2
@Tobia इस दृष्टिकोण का उपयोग kociemba.org/cube.htm को हल करने के लिए N चालों की आवश्यकता के लिए रूबिक के घन पदों की अनुमानित संख्या का पता लगाने के लिए किया गया था, इसलिए इस तरह से एक अनुमान प्राप्त करना संभव है। हालाँकि, अगर मैं एक प्रोग्राम लिखता हूँ जो हर पंक्ति को हल करता है और फिर यह देखने के लिए परीक्षण करता है कि क्या कॉलम और वर्ग हल किए गए हैं, तो इसके पास (9!) ^ 9 = 1E50 bruteforce की संभावनाएँ होंगी, जिनमें से केवल 6E21 हिट हैं (प्रति प्रश्न के अनुसार) ।) इसे औसत पर प्रति हिट 1.6E28 प्रयासों की आवश्यकता होगी। यह बहुत धीमी है। अब, अगर मैं सुनिश्चित कर सकता हूँ कि दोनों पंक्तियाँ और कॉल सही हैं और केवल वर्गों की जाँच करें, तो मैं कहीं जा रहा हूँ। आह! मेरे पास एक विचार है ...
लेवल रिवर सेंट

@steveverrill देखें? :-)
टोबिया

क्या कोई विश्लेषणात्मक समाधान नहीं है?
न्यूब्रिक्ट

जवाबों:


3

सी ++

मैं यहाँ क्या पेश करूँगा एक एल्गोरिथ्म है, जिसे एक 3x3 मामले के उदाहरण के साथ चित्रित किया गया है। यह सैद्धांतिक रूप से NxN मामले में बढ़ाया जा सकता है, लेकिन इसके लिए बहुत अधिक शक्तिशाली कंप्यूटर और / या कुछ सरल जुड़वाँ की आवश्यकता होगी। मैं कुछ सुधारों का उल्लेख करूंगा जैसे ही मैं जाता हूं।

आगे जाने से पहले, सुडोकू ग्रिड के परिवर्तनों पर ध्यान दें । ब्लॉक आकार 3 के लिए, समरूपता निम्नानुसार हैं:

क्षैतिज समरूपता

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

ऊर्ध्वाधर समरूपता

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

ध्यान दें कि ग्रिड के क्षैतिज और ऊर्ध्वाधर प्रतिबिंब इन के संयोजन से प्राप्त किए जा सकते हैं, इसलिए उन्हें गिनने की आवश्यकता नहीं है। माना जाने वाला एक और स्थानिक समरूपता है, जो ट्रांसपोज़िंग है, जो एक कारक है 2। यह कुल स्थानिक समरूपता देता है

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

फिर एक और, बहुत महत्वपूर्ण समरूपता है, जिसे रिलेब्लिंग कहा जाता है।

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

समाधानों की कुल संख्या को इस संख्या द्वारा समरूपता-अद्वितीय समाधानों की संख्या को गुणा करके नहीं पाया जा सकता है, क्योंकि ऑटोमोरफ़िक समाधानों की संख्या (1% से कम) हैं। इसका मतलब है कि इन विशेष समाधानों के लिए एक समरूपता ऑपरेशन है जो उन्हें खुद को मैप करता है, या कई समरूपता ऑपरेशन जो उन्हें उसी दूसरे समाधान में मैप करते हैं।

समाधानों की संख्या का अनुमान लगाने के लिए, मैं समस्या को 4 चरणों में देखता हूं:

1. r[362880][12]0 से 8. की संख्या के सभी संभावित क्रमों के साथ एक सरणी भरें (यह प्रोग्रामिंग है, और यह सी में है, इसलिए हम 1 से 9 का उपयोग नहीं करने जा रहे हैं।) यदि आप चकित हैं तो आप देखेंगे कि दूसरी सबस्क्रिप्ट १२ नहीं ९ है। ऐसा इसलिए है क्योंकि ऐसा करते समय, यह ध्यान में रखते हुए कि हम इसे "पंक्ति" मानने जा रहे हैं, हम तीन और पूर्णांकों की गणना भी करते हैं, r[9,10,11] == 1<<a | 1<<b | 1<<cजहां ९, १०,११ पहले, दूसरे और तीसरे स्टैक का उल्लेख करते हैं। और a, b, c उस पंक्ति के प्रत्येक स्टैक में मौजूद तीन संख्याएँ हैं।

2. b3 पंक्तियों के एक बैंड के सभी संभव समाधान के साथ एक सरणी भरें । इसे यथोचित रूप से छोटा रखने के लिए, केवल उन समाधानों को शामिल करें जहां शीर्ष पंक्ति 012,345,678 है। मैं सभी संभावित मध्य पंक्तियों और एंडिंग r[0][10,11,12]को उत्पन्न करके, जानवर बल द्वारा ऐसा करता हूं r[i][10,11,12]। किसी भी सकारात्मक मान का मतलब है कि एक ही वर्ग में दो समान संख्याएँ हैं और बैंड अमान्य है। जब पहली दो पंक्तियों के लिए एक वैध संयोजन होता है, तो मैं उसी तकनीक के साथ तीसरी (नीचे) पंक्ति खोजता हूं।

मैंने सरणी को b [2000000] [9] के रूप में आयाम दिया लेकिन कार्यक्रम में केवल 1306368 समाधान मिलते हैं। मुझे नहीं पता था कि कितने थे, इसलिए मैंने उस तरह के सरणी आयाम को छोड़ दिया। यह वास्तव में एकल बैंड (विकिपीडिया पर सत्यापित) के लिए केवल आधा संभव समाधान है, क्योंकि मैं केवल iऊपर की ओर के वर्तमान मूल्य से 3 वीं पंक्ति को स्कैन करता हूं । 2 और 3 पंक्तियों के आदान-प्रदान से शेष आधे समाधान तुच्छ रूप से मिल सकते हैं।

जानकारी को सरणी में संग्रहीत करने का तरीका bपहली बार में थोड़ा भ्रमित है। किसी पूर्णांक 0..8में पाए गए संख्याओं को संग्रहीत करने के लिए प्रत्येक पूर्णांक का उपयोग करने के बजाय , यहां प्रत्येक पूर्णांक संख्याओं में से एक पर विचार 0..8करता है और इंगित करता है कि यह किस स्तंभ में पाया जा सकता है। इस प्रकार b[x][7]==100100001यह इंगित करेगा कि समाधान x के लिए नंबर 7 कॉलम 0,5 और 8 (दाएं से बाएं) में पाया जाता है। इस प्रतिनिधित्व का कारण यह है कि हमें बैंड के लिए बाकी की संभावनाओं को रीलेबल करने से उत्पन्न करने की आवश्यकता है, और यह प्रतिनिधित्व यह करने के लिए सुविधाजनक बनाता है।

ऊपर दिए गए दो चरणों में सेटअप शामिल है और लगभग एक मिनट का समय लगता है (यदि मैंने अनावश्यक डेटा आउटपुट को हटा दिया है तो कम हो सकता है। वास्तविक खोज के नीचे दो चरण हैं।)

3 पहले दो बैंडों के समाधान के लिए यादृच्छिक रूप से खोजें जो क्लैश नहीं करते हैं (अर्थात किसी दिए गए कॉलम में दो बार एक ही नंबर नहीं है। हम बैंड 1 के लिए एक यादृच्छिक समाधान चुनते हैं, हमेशा क्रमचय 0 मानते हैं, और बैंड 2 के लिए एक यादृच्छिक समाधान। एक यादृच्छिक क्रमपरिवर्तन। एक परिणाम सामान्य रूप से 9999 से कम (पहले चरण में हजारों की संख्या में हिट दर) की कोशिश में पाया जाता है और एक दूसरे का एक अंश लेता है। क्रमचय के द्वारा, मेरा मतलब है कि दूसरे बैंड के लिए हम बी से एक समाधान लेते हैं।] [] जहां पहली पंक्ति हमेशा 012,345,678 होती है और इसे रीलेबल किया जाता है ताकि पहली पंक्ति में संख्याओं का कोई भी संभावित अनुक्रम संभव हो।

4 जब चरण 3 में एक हिट पाया जाता है, तो तीसरे बैंड के लिए एक समाधान की तलाश करें जो अन्य दो के साथ नहीं टकराता है। हम केवल एक कोशिश नहीं करना चाहते हैं, अन्यथा चरण 3 के लिए प्रसंस्करण समय बर्बाद हो जाएगा। दूसरी ओर हम इस प्रयास में एक अयोग्य राशि नहीं डालना चाहते हैं।

बस मज़े के लिए, कल रात मैंने इसे सबसे विनम्र तरीके से संभव किया, लेकिन यह अभी भी दिलचस्प था (क्योंकि यह उम्र के लिए कुछ भी नहीं है, फिर फटने में बड़ी संख्या में समाधान पाए गए।) एक डाटापॉइंट पाने में सारी रात लगी, यहां तक ​​कि छोटे के साथ भी। (!z)मैंने अंतिम kलूप को समाप्त करने के लिए किया था जब तक हम जानते हैं कि यह एक वैध समाधान नहीं है (जो इसे लगभग 9 गुना तेज चलाता है।) इसने पूर्ण ग्रिड के लिए 1186585 समाधान खोजे थे, जो सभी 1306368 के सभी 362880 relabellings को खोजने के बाद अंतिम समाधान के लिए। ब्लॉक, कुल 474054819840 संभावनाएं। यह दूसरे चरण के लिए 400000 में 1 की हिट दर है। मैं स्कैन के बजाय एक यादृच्छिक खोज के साथ जल्द ही फिर से कोशिश करूंगा। इसे कुछ मिलियन कोशिशों में उचित जवाब देना चाहिए, जिसमें केवल कुछ सेकंड लगने चाहिए।

समग्र उत्तर (362880 * (1306368 * 2)) ^ 3 * हिट दर = 8.5E35 * हिट दर होना चाहिए। सवाल में संख्या से वापस गणना करके, मैं 1 / 1.2E14 की हिट दर की उम्मीद करता हूं। मैंने अपने एकल डेटापॉइंट के साथ अब तक जो भी प्राप्त किया है वह 1 / (400000 * 1000) है जो लगभग एक मिलियन के कारक से बाहर है। यह संयोग की विसंगति, मेरे कार्यक्रम में त्रुटि या मेरे गणित में त्रुटि हो सकती है। मुझे नहीं पता होगा कि यह तब तक है जब तक मैं कुछ और परीक्षण नहीं करता।

मैं इसे आज रात के लिए यहाँ छोड़ दूँगा। पाठ थोड़ा डरावना है, मैं इसे जल्द ही साफ कर दूंगा और उम्मीद है कि कुछ और परिणाम जोड़ेंगे, और हो सकता है कि इसे तेजी से कैसे बनाया जाए और अवधारणा को N = 4 तक कैसे बढ़ाया जाए, इस पर कुछ शब्द। मुझे नहीं लगता कि मैं अपने कार्यक्रम में बहुत अधिक बदलाव कर रहा हूं, हालांकि :-)

आह .. कार्यक्रम:

#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();
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.