सी ++
मैं यहाँ क्या पेश करूँगा एक एल्गोरिथ्म है, जिसे एक 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. b
3 पंक्तियों के एक बैंड के सभी संभव समाधान के साथ एक सरणी भरें । इसे यथोचित रूप से छोटा रखने के लिए, केवल उन समाधानों को शामिल करें जहां शीर्ष पंक्ति 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();
}