सबसे कम समय में इस नंबर पहेली के लिए सभी समाधान खोजें


16

इतिहास

मेरी कंपनी कंपनी के भीतर सभी को एक साप्ताहिक समाचार पत्र भेजती है। इन न्यूज़लेटर्स में शामिल एक पहेली है, कंपनी में एक चिल्लाहट के साथ पिछले हफ्ते की पहेली को ईमेल / समाधान प्रदान करने वाला पहला ईमेल था। इन पहेलियों में से अधिकांश काफी तुच्छ हैं, और ईमानदारी से एक तकनीकी कंपनी के लिए बहुत सुस्त हैं, लेकिन कई महीने पहले एक था, जिसने मेरा ध्यान आकर्षित किया।

मूल पहेली:

नीचे दिए गए आकार को देखते हुए:

पहेली छवि

आपके पास 1 से 16 तक प्राकृतिक संख्याएँ हैं। उन सभी को इस आकार में फिट करें, जैसे कि सभी सन्निहित पंक्तियों और सन्निहित स्तंभों का योग 29 तक हो।

उदाहरण के लिए, इस पहेली का एक ऐसा समाधान (जो समाचार पत्र को मैंने प्रस्तुत "विहित" समाधान था) निम्नलिखित था:

हल की गई पहेली चित्र

हालाँकि, इसे हल करने के दौरान, मुझे कुछ रोचक जानकारी मिली:

  • केवल एक से अधिक महत्वपूर्ण समाधान हैं; वास्तव में, 9,368 समाधान हैं।
  • यदि आप नियम का विस्तार केवल इस बात के लिए करते हैं कि पंक्तियाँ और स्तंभ एक दूसरे के बराबर हों, तो जरूरी नहीं कि 29 ही हों, आपको 33,608 समाधान मिलते हैं:
    • 27 की राशि के लिए 4,440 समाधान।
    • 28 के योग के लिए 7,400 समाधान।
    • 29 की राशि के लिए 9,368 समाधान।
    • 30 की राशि के लिए 6,096 समाधान।
    • 31 की राशि के लिए 5,104 समाधान।
    • 32 की राशि के लिए 1,200 समाधान।

इसलिए मैं और मेरे सहकर्मी (हालांकि ज्यादातर सिर्फ मेरे प्रबंधक थे, क्योंकि वह "जनरल पर्पस" प्रोग्रामिंग कौशल के साथ मेरे अलावा एकमात्र व्यक्ति थे) जो एक चुनौती पर सेट हुए थे, जो कि महीने के अधिकांश समय तक चलता था- हमारे पास अन्य, वास्तविक नौकरी थी- संबंधित दायित्वों को हमें एक कार्यक्रम लिखने की कोशिश करने के लिए उपस्थित होना था - जो हर एक समाधान को सबसे तेज़ तरीके से संभव करेगा।

मूल सांख्यिकी

समस्या को हल करने के लिए मैंने जो पहला कार्यक्रम लिखा था, उसने बस और अधिक से अधिक यादृच्छिक समाधानों की जाँच की, और जब इसका हल मिला तो रुक गया। यदि आपने इस समस्या पर गणितीय विश्लेषण किया है, तो आप शायद पहले से ही जानते हैं कि यह काम नहीं करना चाहिए था; लेकिन किसी तरह मैं भाग्यशाली हो गया, और एकल समाधान खोजने के लिए कार्यक्रम में केवल एक मिनट लगा (जो मैंने ऊपर पोस्ट किया था)। कार्यक्रम के रिपीट रन अक्सर 10 या 20 मिनट लगते हैं, तो जाहिर है कि यह समस्या का कठोर समाधान नहीं था।

मैंने एक पुनरावर्ती समाधान पर स्विच किया, जो पहेली के हर संभव क्रमांकन के माध्यम से पुनरावृत्त हुआ, और कई समाधानों को एक बार में समाप्त कर दिया, जो जोड़ नहीं रहे थे। IE अगर पहली पंक्ति / कॉलम की तुलना मैं पहले से ही बराबर नहीं कर रहा था, तो मैं तुरंत उस शाखा की जांच करना बंद कर सकता हूं, यह जानकर कि पहेली में अनुमति दी गई और कुछ भी नहीं बदलेगा।

इस एल्गोरिथ्म का उपयोग करते हुए, मुझे पहली "उचित" सफलता मिली: कार्यक्रम लगभग 5 मिनट में सभी 33,608 समाधान उत्पन्न कर सकता है और थूक सकता है।

मेरे प्रबंधक का एक अलग दृष्टिकोण था: मेरे काम के आधार पर यह जानते हुए कि एकमात्र संभव समाधान में 27, 28, 29, 30, 31, या 32 के योग थे, उन्होंने एक बहु-थ्रेडेड समाधान लिखा था जो केवल उन विशिष्ट मूल्यों के लिए संभव रकम की जाँच करता था। वह केवल 2 मिनट में अपना कार्यक्रम चलाने में सफल रहे। तो मैं फिर से iterated; मैंने सभी संभावित 3/4 अंकों के योग (कार्यक्रम की शुरुआत में; इसे कुल क्रम में गिना जाता है) और पहले से तैयार पंक्ति के आधार पर शेष मूल्य को देखने के लिए एक पंक्ति के "आंशिक योग" का उपयोग किया, बजाय सभी शेष मूल्यों का परीक्षण, और 72 सेकंड के लिए समय नीचे लाया। फिर कुछ मल्टी-थ्रेडिंग लॉजिक के साथ, मैंने इसे 40 सेकंड तक नीचे ला दिया। मेरे प्रबंधक ने कार्यक्रम को घर ले लिया, कार्यक्रम चलाने के तरीके के बारे में कुछ अनुकूलन किए, और 12 सेकंड के लिए नीचे उतर गए। मैंने पंक्तियों और स्तंभों के मूल्यांकन को फिर से व्यवस्थित किया,

एक महीने के बाद हमारे कार्यक्रमों में से सबसे तेज़ हमारे प्रबंधक के लिए 0.15 सेकंड और मेरे लिए 0.33 सेकंड था। मैं दावा है कि मेरा कार्यक्रम है, तेजी से हालांकि था मेरे प्रबंधक के कार्यक्रम के बाद समाप्त हो गया है, जबकि यह किया लगता है सब समाधान, उन्हें एक पाठ फ़ाइल में बाहर मुद्रण नहीं किया गया। यदि उन्होंने उस तर्क को अपने कोड में जोड़ा, तो यह अक्सर 0.4-0.5 सेकंड से ऊपर हो जाता है।

चूंकि हमने अपनी अंतर-व्यक्तिगत चुनौती को निर्वाह करने की अनुमति दी है, लेकिन निश्चित रूप से, यह सवाल बना हुआ है: क्या इस कार्यक्रम को तेज बनाया जा सकता है?

यही चुनौती मैं आप लोगों को देने जा रहा हूं।

आपकी चुनौती

पैरामीटर हमने "29 के योग" नियम के तहत "सभी पंक्तियों / स्तंभों के बराबर" के रूप में आराम से काम किया है, और मैं उस नियम को आप लोगों के लिए भी सेट करने जा रहा हूं। चुनौती, इसलिए है: एक प्रोग्राम लिखें जो इस (और प्रिंट्स!) को कम से कम समय में इस पहेली को हल करता है। मैं प्रस्तुत समाधानों पर एक सीलिंग स्थापित करने जा रहा हूं: यदि कार्यक्रम अपेक्षाकृत सभ्य कंप्यूटर (<8 वर्ष) पर 10 सेकंड से अधिक समय लेता है, तो संभवतः इसे गिना जाना बहुत धीमा है।

इसके अलावा, मेरे पास पहेली के लिए कुछ बोनस हैं:

  • क्या आप समाधान को सामान्य कर सकते हैं ताकि यह 16 नंबरों के किसी भी सेट के लिए काम करे, न कि सिर्फ int[1,16]? टाइमिंग स्कोर का मूल्यांकन मूल प्रॉम्प्ट संख्या सेट के आधार पर किया जाएगा, लेकिन इस कोडपथ के माध्यम से पारित किया गया। (-10%)
  • क्या आप कोड को इस तरह से लिख सकते हैं कि वह सुंदर तरीके से डुप्लिकेट संख्याओं के साथ संभालता है और हल करता है? यह उतना सरल नहीं है जितना कि यह प्रतीत हो सकता है! समाधान जो "नेत्रहीन समान हैं" परिणाम सेट में अद्वितीय होना चाहिए। (-5%)
  • क्या आप नकारात्मक संख्या को संभाल सकते हैं? (-5%)

आप एक समाधान बनाने की कोशिश भी कर सकते हैं जो फ्लोटिंग-पॉइंट नंबरों को संभालता है, लेकिन निश्चित रूप से, अगर यह पूरी तरह से विफल रहता है तो चौंकें नहीं। यदि आप एक मजबूत समाधान हालांकि, कि एक बड़े बोनस के लायक हो सकता है!

सभी इरादों और उद्देश्यों के लिए, "घुमाव" को अद्वितीय समाधान माना जाता है। तो एक समाधान जो केवल एक अलग समाधान का एक रोटेशन है, अपने स्वयं के समाधान के रूप में गिना जाता है।

मेरे कंप्यूटर पर मेरे द्वारा काम की जाने वाली IDE जावा और C ++ हैं। मैं अन्य भाषाओं से उत्तर स्वीकार कर सकता हूं, लेकिन आपको एक लिंक भी प्रदान करना पड़ सकता है जहां मुझे आपके कोड के लिए एक आसान-से-सेटअप रनटाइम वातावरण मिल सकता है।


3
पवित्र बिल्लियों, अच्छा पहला सवाल! ... बोनस को छोड़कर, जिसे हम सॉर्ट-हतोत्साहित करते हैं (ज्यादातर कोड-गोल्फ सवालों पर, इसलिए उन्हें यहां ठीक होना चाहिए)
बिल्ली

4
@ मुझे लगता है कि बोनस यहां समझ में आता है, क्योंकि जब मैंने उन मुद्दों को अपने कोड में हल किया, तो वे एक महत्वपूर्ण तरीके से कोड को धीमा करने का कारण बन गए। इसलिए मुझे लगता है कि समावेश को सही ठहराने के लिए एक बोनस है।
Xirema

2
BTW, क्या आपके स्थान पर कोई नौकरी चल रही है? ऐसा लगता है कि आपके पास एक आसान बॉस है और आपके हाथों पर बहुत समय है :-)
लेवल रिवर सेंट

1
डुप्लिकेट संख्याओं के साथ, क्या डुप्लिकेट समाधान प्रिंट करना ठीक है जहां दो समान संख्याओं का आदान-प्रदान होता है? यह एक बड़ा अंतर होगा कि कैसे उस बोनस की व्याख्या की जाती है। कृपया स्पष्ट करें, लेकिन मैं उस बोनस को पूरी तरह से समाप्त करने पर विचार करूंगा।
स्तर नदी सेंट

1
इसके अलावा, 180 डिग्री रोटेशन को एक ही समाधान या विभिन्न समाधान माना जाता है?
लेवल रिवर सेंट

जवाबों:


7

सी - 0.5 सेकंड के पास

यह बहुत ही भोली कार्यक्रम मेरे 4 साल पुराने लैपटॉप पर आधे सेकंड में सभी समाधान देता है। कोई मल्टीथ्रेड, कोई हैशिंग नहीं।

विंडोज 10, विजुअल स्टूडियो 2010, सीपीयू कोर आई 7 64 बिट

Ideone पर ऑनलाइन प्रयास करें

#include <stdio.h>
#include <time.h>

int inuse[16];
int results[16+15+14];

FILE *fout;

int check(int number)
{
    if (number > 0 && number < 17 && !inuse[number-1])
    {
        return inuse[number-1]=1;
    }
    return 0;
}

void free(int number)
{
    inuse[number-1]=0;
}

void out(int t, int* p)
{
    int i;
    fprintf(fout, "\n%d",t);
    for(i=0; i< 16; i++) fprintf(fout, " %d",*p++);
}

void scan() 
{
    int p[16];
    int t,i;
    for (p[0]=0; p[0]++<16;) if (check(p[0]))
    {
        for (p[1]=0; p[1]++<16;) if (check(p[1]))
        {
            for (p[2]=0; p[2]++<16;) if (check(p[2]))
            {
                t = p[0]+p[1]+p[2]; // top horiz: 0,1,2
                for (p[7]=0; p[7]++<16;) if (check(p[7]))
                {
                    if (check(p[11] = t-p[7]-p[2])) // right vert: 2,7,11
                    {
                        for(p[9]=0; p[9]++<16;) if (check(p[9]))
                        {
                            for (p[10]=0; p[10]++<16;) if (check(p[10]))
                            {
                                if (check(p[12] = t-p[9]-p[10]-p[11])) // right horiz: 9,10,11,12
                                {
                                    for(p[6]=0; p[6]++<16;) if (check(p[6]))
                                    {
                                        if (check(p[15] = t-p[0]-p[6]-p[9])) // middle vert: 0,6,9,15
                                        {
                                            for(p[13]=0; p[13]++<16;) if (check(p[13]))
                                            {
                                                if (check(p[14] = t-p[13]-p[15])) // bottom horiz:  13,14,15
                                                {
                                                    for(p[4]=0; p[4]++<16;) if (check(p[4]))
                                                    {
                                                        if (check(p[8] = t-p[4]-p[13])) // left vert: 4,8,13
                                                        {
                                                            for(p[3]=0; p[3]++<16;) if (check(p[3]))
                                                            {
                                                                if (check(p[5] = t-p[3]-p[4]-p[6])) // left horiz: 3,4,5,6
                                                                {
                                                                    ++results[t];
                                                                    out(t,p);
                                                                    free(p[5]);
                                                                }
                                                                free(p[3]);
                                                            }
                                                            free(p[8]);
                                                        }
                                                        free(p[4]);
                                                    }
                                                    free(p[14]);
                                                }
                                                free(p[13]);
                                            }
                                            free(p[15]);
                                        }
                                        free(p[6]);
                                    }
                                    free(p[12]);
                                }
                                free(p[10]);
                            }
                            free(p[9]);
                        }
                        free(p[11]);
                    }
                    free(p[7]);
                }    
                free(p[2]);
            } 
            free(p[1]);
        }
        free(p[0]);
    }
    for(i=0;i<15+16+14;i++)
    {
        if(results[i]) printf("%d %d\n", i, results[i]);
    }
}

void main()
{
    clock_t begin, end;
    double time_spent;
    begin = clock();

    fout = fopen("c:\\temp\\puzzle29.txt", "w");
    scan();
    fclose(fout);

    end = clock();
    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("Time %g sec\n", time_spent);
}

पवित्र मिठाई ईविल वैम्पिरिक यीशु, जो छोरों के लिए नेस्टेड थे। मुझे यकीन है कि अपने संकलक हालांकि वास्तव में खुश कर दिया। XD
Xirema

@ edc65, FYI करें आप int inuse[16];बस के साथ बदल सकते हैं int inuse;और फिर इसे हेरफेर करने के लिए बिटवाइज़ ऑपरेटरों का उपयोग कर सकते हैं। यह गति बढ़ाने के लिए प्रतीत नहीं होता है कि बहुत है, लेकिन यह एक छोटे से मदद करता है।
एंड्रयू एपस्टीन

@AndrewEpstein यह भी धीमी हो सकती है
बिटशफ्ट

@ edc65, मैंने आपके मूल संस्करण बनाम बिटशिफ्ट संस्करण का परीक्षण करने के लिए डंबबेक का उपयोग करने की स्वतंत्रता ली । परिणाम इस प्रकार हैं: अनुक्रमण: 0.2253 +/- 5.7590e-05 बिट्स शिफ्टिंग: 0.2093 +/- 6.6595e-05 तो, मेरी मशीन पर लगभग 16ms स्पीडअप। मेरे द्वारा उपयोग की जाने वाली कमांड थी:dumbbench --precision=.01 -vvv --initial=500 ./solve
एंड्रयू एपस्टीन

3

सी ++ - 300 मिलीसेकंड

अनुरोध के अनुसार, मैंने इस पहेली को हल करने के लिए अपना स्वयं का कोड जोड़ा है। मेरे कंप्यूटर पर, यह 0.310 सेकंड (310 मिलीसेकंड) के औसत पर घड़ी है लेकिन विचरण के आधार पर 287 मिलीसेकंड के रूप में जल्दी से चल सकता है। मैं शायद ही कभी इसे 350 मिलीसेकंड से ऊपर उठता हुआ देखता हूं, आमतौर पर केवल तभी जब मेरा सिस्टम एक अलग कार्य से टकरा जाता है।

ये समय कार्यक्रम में प्रयुक्त स्व-रिपोर्टिंग पर आधारित हैं, लेकिन मैंने बाहरी टाइमर का उपयोग करके भी परीक्षण किया और समान परिणाम प्राप्त किए। कार्यक्रम में ओवरहेड लगभग 10 मिलीसेकंड जोड़ने के लिए लगता है।

इसके अलावा, मेरे कोड नहीं है काफी सही ढंग से डुप्लिकेट संभाल। यह उनका उपयोग करके हल कर सकता है, लेकिन यह समाधान सेट से "नेत्रहीन समान" समाधानों को समाप्त नहीं करता है।

#include<iostream>
#include<vector>
#include<random>
#include<functional>
#include<unordered_set>
#include<unordered_map>
#include<array>
#include<thread>
#include<chrono>
#include<fstream>
#include<iomanip>
#include<string>
#include<mutex>
#include<queue>
#include<sstream>
#include<utility>
#include<atomic>
#include<algorithm>

//#define REDUCE_MEMORY_USE

typedef std::pair<int, std::vector<std::pair<int, int>>> sumlist;
typedef std::unordered_map<int, std::vector<std::pair<int, int>>> summap;
typedef std::array<int, 16> solution_space;

class static_solution_state {
public:
    std::array<int, 16> validNumbers;
    summap twosums;
    size_t padding;
    std::string spacing;

    static_solution_state(const std::array<int, 16> & _valid);

    summap gettwovaluesums();
    std::vector<sumlist> gettwovaluesumsvector();
};

static_solution_state::static_solution_state(const std::array<int, 16> & _valid) 
    : validNumbers(_valid) {
    twosums = gettwovaluesums();
    padding = 0;
    for (int i = 0; i < 16; i++) {
        size_t count = std::to_string(validNumbers[i]).size();
        if (padding <= count) padding = count + 1;
    }
    spacing.resize(padding, ' ');
}

class solution_state {
private:
    const static_solution_state * static_state;
public:
    std::array<int, 16> currentSolution;
    std::array<bool, 16> used;
    std::array<int, 7> sums;
    size_t solutions_found;
    size_t permutations_found;
    size_t level;
    std::ostream * log;

    solution_state(const static_solution_state & _sstate);
    solution_state(static_solution_state & _sstate) = delete;
    void setLog(std::ostream & out);
    const int & operator[](size_t index) const;

};

solution_state::solution_state(const static_solution_state & _sstate) {
    static_state = &_sstate;
    sums = { 0 };
    used = { false };
    currentSolution = { -1 };
    solutions_found = 0;
    permutations_found = 0;
    level = 0;
}

void solution_state::setLog(std::ostream & out) {
    log = &out;
}

const int & solution_state::operator[](size_t index) const {
    return static_state->validNumbers[currentSolution[index]];
}

int getincompletetwosum(const static_solution_state & static_state, const solution_state & state);
void permute(const static_solution_state & static_state, solution_state & state, volatile bool & reportProgress, const volatile size_t & total_tests, volatile bool & done);
void setupOutput(std::fstream & out);
void printSolution(const static_solution_state & static_state, const solution_state & state);
constexpr size_t factorial(const size_t iter);

const bool findnext2digits[16]{
    false, false, false,
    true, false,
    false, true, false,
    true, false,
    true, false,
    true, false,
    true, false
};

const int currentsum[16]{
    0, 0, 0,
    1, 1,
    2, 2, 2,
    3, 3,
    4, 4,
    5, 5,
    6, 6
};

const int twosumindexes[7][2]{
    { 0, -1},
    { 2, -1},
    { 5, -1},
    { 5, -1},
    { 0,  7},
    { 11, 4},
    { 10, 9}
};

const std::array<size_t, 17> facttable = [] {
    std::array<size_t, 17> table;
    for (int i = 0; i < 17; i++) table[i] = factorial(i);
    return table;
}();

const int adj = 1;

std::thread::id t1id;

int main(int argc, char** argv) {
    //std::ios_base::sync_with_stdio(false);
    std::array<int, 16> values = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
    if (argc == 17) {
        for (int i = 0; i < 16; i++) {
            values[i] = atoi(argv[i + 1]);
        }
    }
    auto start = std::chrono::high_resolution_clock::now();
    const static_solution_state static_state(values);
#if defined(REDUCE_MEMORY_USE)
    const int num_of_threads = max(1u, min(thread::hardware_concurrency(), 16u));
#else
    const int num_of_threads = 16;
#endif
    std::vector<solution_state> states(num_of_threads, static_state);
    for (int i = 0; i < num_of_threads; i++) {
        int start = i * 16 / num_of_threads;
        states[i].permutations_found += start * factorial(16) / 16;
    }
    std::fstream out;
    setupOutput(out);
    std::locale loc("");
    std::cout.imbue(loc);
    volatile bool report = false;
    volatile bool done = false;
    volatile size_t tests = 0;

    std::thread progress([&]() {
        auto now = std::chrono::steady_clock::now();
        while (!done) {
            if (std::chrono::steady_clock::now() - now > std::chrono::seconds(1)) {
                now += std::chrono::seconds(1);

                size_t t_tests = 0;
                for (int i = 0; i < num_of_threads; i++) t_tests += states[i].permutations_found - i * factorial(16) / num_of_threads;
                tests = t_tests;
                report = true;
            }
            std::this_thread::yield();
        }
    });

    if (num_of_threads <= 1) {


        states[0].setLog(out);
        permute(static_state, states[0], report, tests, done);


    } 
    else {
        std::vector<std::thread> threads;
#if defined(REDUCE_MEMORY_USE)
        std::vector<std::fstream> logs(num_of_threads);
#else
        std::vector<std::stringstream> logs(num_of_threads);
#endif
        for (int i = 0; i < num_of_threads; i++) {
            threads.emplace_back([&, i]() {
                if (i == 0) t1id = std::this_thread::get_id();
                int start = i * 16 / num_of_threads;
                int end = (i + 1) * 16 / num_of_threads;
#if defined(REDUCE_MEMORY_USE)
                logs[i].open("T"s + to_string(i) + "log.tmp", ios::out);
#endif
                logs[i].imbue(loc);
                states[i].setLog(logs[i]);

                for (int j = start; j < end; j++) {


                    states[i].currentSolution = { j };
                    states[i].level = 1;
                    states[i].used[j] = true;
                    permute(static_state, states[i], report, tests, done);


                }
            });
        }

        std::string buffer;
        for (int i = 0; i < num_of_threads; i++) {
            threads[i].join();
#if defined(REDUCE_MEMORY_USE)
            logs[i].close();
            logs[i].open("T"s + to_string(i) + "log.tmp", ios::in);
            logs[i].seekg(0, ios::end);
            auto length = logs[i].tellg();
            logs[i].seekg(0, ios::beg);
            buffer.resize(length);
            logs[i].read(&buffer[0], length);
            logs[i].close();
            remove(("T"s + to_string(i) + "log.tmp").c_str());
            out << buffer;
#else
            out << logs[i].str();
#endif
        }
    }
    done = true;
    out.close();

    if (num_of_threads > 1) {
        size_t t_tests = 0;
        for (int i = 0; i < num_of_threads; i++) t_tests += states[i].permutations_found - i * factorial(16) / num_of_threads;
        tests = t_tests;
    }

    size_t solutions = 0;
    for (const auto & state : states) {
        solutions += state.solutions_found;
    }

    auto end = std::chrono::high_resolution_clock::now();

    progress.join();

    auto duration = end - start;
    auto secondsDuration = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
    std::cout << "Total time to process all " << tests << " results: " << std::setprecision(3) << std::setiosflags(std::ostream::fixed) << (secondsDuration.count()/1000.0) << "s" << "\n";
    std::cout << "Solutions found: " << solutions << std::endl;
    //system("pause");
    return 0;
}

void permute(const static_solution_state & static_state, solution_state & state, volatile bool & reportProgress, const volatile size_t & total_tests, volatile bool & done) {
    if (done) return;
    if (state.level >= 16) {
        if (reportProgress) {
            reportProgress = false;
            std::cout << "Current Status:" << "\n";
            std::cout << "Test " << total_tests << "\n";
            std::cout << "Contents: {";
            for (int i = 0; i < 15; i++) std::cout << std::setw(static_state.padding - 1) << state[i] << ",";
            std::cout << std::setw(static_state.padding - 1) << state[15] << "}" << "(Partial Sum: " << state.sums[0] << ")" << "\n";
            std::cout << "=====================" << "\n";
        }
        printSolution(static_state,state);
        state.solutions_found++;
        state.permutations_found++;
    }
    else {
        if (state.level == 3) state.sums[0] = state[0] + state[1] + state[2];

        if (!findnext2digits[state.level]) {
            for (int i = 0; i < 16; i++) {
                if (!state.used[i]) {
                    state.currentSolution[state.level] = i;
                    state.used[i] = true;
                    state.level++;
                    permute(static_state, state, reportProgress, total_tests, done);
                    state.level--;
                    state.used[i] = false;
                }
            }
        }
        else {
            int incompletetwosum = getincompletetwosum(static_state, state);
            if (static_state.twosums.find(incompletetwosum) == static_state.twosums.end()) {
                state.permutations_found += facttable[16 - state.level];
            }
            else {
                size_t successes = 0;
                const std::vector<std::pair<int, int>> & potentialpairs = static_state.twosums.at(incompletetwosum);
                for (const std::pair<int, int> & values : potentialpairs) {
                    if (!state.used[values.first] && !state.used[values.second]) {
                        state.currentSolution[state.level] = values.first;
                        state.currentSolution[state.level + 1] = values.second;
                        state.used[values.first] = true;
                        state.used[values.second] = true;
                        state.level += 2;
                        permute(static_state, state, reportProgress, total_tests, done);
                        state.level -= 2;
                        state.used[values.first] = false;
                        state.used[values.second] = false;

                        successes++;
                    }
                }
                state.permutations_found += facttable[16 - state.level - 2] * ((16 - state.level) * (15 - state.level) - successes); 
            }
        }
    }
}

int getincompletetwosum(const static_solution_state & static_state, const solution_state & state) {
    int retvalue = state.sums[0];
    int thissum = currentsum[state.level];
    for (int i = 0; i < 2 && twosumindexes[thissum][i] >= 0; i++) {
        retvalue -= state[twosumindexes[thissum][i]];
    }
    return retvalue;
}

constexpr size_t factorial(size_t iter) {
    return (iter <= 0) ? 1 : iter * factorial(iter - 1);
}

void setupOutput(std::fstream & out) {
    out.open("puzzle.txt", std::ios::out | std::ios::trunc);
    std::locale loc("");
    out.imbue(loc);
}

void printSolution(const static_solution_state & static_state, const solution_state & state) {
    std::ostream & out = *state.log;
    out << "Test " << state.permutations_found << "\n";
    static const auto format = [](std::ostream & out, const static_solution_state & static_state, const solution_state & state, const std::vector<int> & inputs) {
        for (const int & index : inputs) {
            if (index < 0 || index >= 16) out << static_state.spacing;
            else out
                << std::setw(static_state.padding)
                << state[index];
        }
        out << "\n";
    };
    format(out, static_state, state, { -1, -1, -1,  0,  1,  2 });
    format(out, static_state, state, { 15,  9, 14, 10, -1,  3 });
    format(out, static_state, state, { -1,  8, -1, 11, 12,  4, 13 });
    format(out, static_state, state, { -1,  5,  6,  7});

    out << "Partial Sum: " << (state.sums[0]) << "\n";
    out << "=============================" << "\n";
}

summap static_solution_state::gettwovaluesums() {
    summap sums;
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 16; j++) {
            if (i == j) continue;
            std::pair<int,int> values( i, j );
            int sum = validNumbers[values.first] + validNumbers[values.second];
            sums[sum].push_back(values);
        }
    }
    return sums;
}

std::vector<sumlist> static_solution_state::gettwovaluesumsvector() {
    std::vector<sumlist> sums;
    for (auto & key : twosums) {
        sums.push_back(key);
    }

    std::sort(sums.begin(), sums.end(), [](sumlist a, sumlist b) {
        return a.first < b.first;
    });
    return sums;
}

जैसा कि मुझे यकीन है कि आप जागरूक हैं, यदि आप अपने उत्पादन को थोड़ा सरल करते हैं, तो आप समय की एक सभ्य राशि से दाढ़ी बना सकते हैं। यहां आपके कोड का समय है: 0.1038s +/- 0.0002 और यहां सरलीकृत आउटपुट के साथ आपके कोड का समय है: 0.0850s +/- 0.0001 तो, आप ~ 18ms बचा सकते हैं, कम से कम मेरी मशीन पर। मैंने दोनों संस्करणों को 500+ बार दौड़ाया
एंड्रयू एपस्टीन

1

प्रोलोग - 3 मिनट

इस तरह की पहेली प्रोलॉग के लिए एक सही उपयोग-केस की तरह लगती है। तो, मैं Prolog में एक समाधान कोडित! यह रहा:

:- use_module(library(clpfd)).

puzzle(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) :-
    Vars = [P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15],
    Vars ins 1..16,
    all_different(Vars),
    29 #= P0 + P1 + P2,
    29 #= P3 + P4 + P5 + P6,
    29 #= P9 + P10 + P11 + P12,
    29 #= P13 + P14 + P15,
    29 #= P0 + P6 + P9 + P15,
    29 #= P2 + P7 + P11,
    29 #= P4 + P8 + P13.

दुर्भाग्य से, यह उतना तेज़ नहीं है जितना मुझे उम्मीद थी। हो सकता है कि कोई और अधिक अच्छी तरह से घोषणात्मक प्रोग्रामिंग (या विशेष रूप से प्रोलॉग) में निपुण हो, कुछ अनुकूलन सुझाव दे सकता है। आप puzzleनिम्न आदेश के साथ नियम को लागू कर सकते हैं :

time(aggregate_all(count, (puzzle(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15), labeling([leftmost, up, enum], [P9, P15, P13, P0, P4, P2, P6, P11, P1, P5, P3, P7, P14, P12, P10, P8])), Count)).

इसे यहाँ ऑनलाइन देखें । आप 29सभी समाधान उत्पन्न करने के लिए कोड में s के स्थान पर किसी भी संख्या को प्रतिस्थापित कर सकते हैं। जैसा कि यह खड़ा है, सभी 29-समाधान लगभग 30 सेकंड में पाए जाते हैं, इसलिए सभी संभावित समाधान खोजने के लिए लगभग 3 मिनट होना चाहिए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.