एक शतरंज बोर्ड पर बहुत सारे मोहरे


10

एक पूर्णांक 2n को देखते हुए, संभावित तरीकों की संख्या ज्ञात करें जिसमें 2n ^ 2 काले प्यादे और 2n ^ 2 सफ़ेद प्यादों को 2n द्वारा 2n शतरंज बोर्ड पर व्यवस्थित किया जा सकता है ताकि कोई अन्य मोहरा हमला न करें।

  • एक काला मोहरा केवल एक सफेद मोहरा, और इसके विपरीत हमला कर सकता है।
  • हमला करने के सामान्य शतरंज के नियम, यानी, सफेद पंजे के हमले तुरंत सामने तिरछे हो जाते हैं, और काले पंजे के हमले तुरंत तिरछे (जैसा कि सफेद पर्यवेक्षक द्वारा देखा जाता है) चौकों पर हमला करते हैं।
  • सभी रोटेशन, प्रतिबिंब अलग के रूप में गिनती।

वह प्रोग्राम जो 120 सेकंड में 2n के उच्चतम मूल्य के लिए सभी संभव कॉन्फ़िगरेशन को आउटपुट कर सकता है। (सभी कार्यक्रमों का स्वागत है, हालांकि)

उदाहरण के लिए, ऐलिस का कार्यक्रम 120 सेकंड के भीतर n = 16 तक निपट सकता है जबकि बॉब एक ​​ही समय में n = 20 तक निपट सकता है। बॉब जीतता है।

प्लेटफ़ॉर्म: लिनक्स 2.7GHz @ 4 सीपीयू


2
आउटपुट स्वरूप क्या है?
दरवाज़े

2
परीक्षण के लिए: क्या किसी के पास संख्याओं का कोई विचार है? मुझे 2x2 के लिए 3 समाधान और 4x4 के लिए 28 समाधान
edc65

1
@ edc65, मैं इसे 3, 30, 410 बनाता हूं। मैंने एक वैकल्पिक विधि द्वारा 3 और 30 की जाँच की है।
पीटर टेलर

1
मेरे पास मेरा कोड पहले कुछ उत्पन्न करता था: 3, 30, 410, 6148, 96120, 1526700। हालांकि, मेरे पास जांच का कोई तरीका नहीं है। किसी को भी वही मिलता है?
cmxu

1
ऑपरेटर की पूर्वता पर स्पष्ट करने के लिए, जब आप कहते 2n^2हैं कि प्यादे, वह है (2n)^2या 2(n^2)?
रेटो कोराडी

जवाबों:


9

मेरी मशीन पर जावा, एन = 87

N = 87 के लिए परिणाम है

62688341832480765224168252369740581641682638216282495398959252035334029997073369148728772291668336432168


import java.math.BigInteger;

public class NonattackingPawns {

    static BigInteger count(int n) {
        BigInteger[][] a0 = new BigInteger[n+1][n*n+1], a1 = new BigInteger[n+1][n*n+1], tm;

        for(int h = 0; h <= n; h++) a0[h][0] = h%2==0? BigInteger.ONE: BigInteger.ZERO;

        for(int c = 1; c <= 2*n; c++) {     
            int minp = 0;
            for(int h = 0; h <= n; h++) {
                java.util.Arrays.fill(a1[h], BigInteger.ZERO);
                if(h>0) minp += c >= 2*h-c%2 ? 2*h - c%2 : c;

                int maxp = Math.min(n*(c-1)+h, n*n);
                for(int p = minp; p <= maxp; p++) {
                    BigInteger sum = a0[h][p-h];

                    if(c%2==1 && h>0) 
                        sum = sum.add(a0[h-1][p-h]);
                    else if(c%2==0 && h<n) 
                        sum = sum.add(a0[h+1][p-h]);

                    a1[h][p] = sum;
                }
            }
            tm=a0; a0=a1; a1=tm;
        }
        BigInteger[] s = new BigInteger[n*n+1];
        for(int p = 0; p <= n*n; p++) {
            BigInteger sum = BigInteger.ZERO;
            for(int h = 0; h <= n; h++) sum = sum.add(a0[h][p]);
            s[p] = sum;

        }

        BigInteger ans = BigInteger.ZERO;
        for(int p = 0; p < n*n; p++) ans = ans.add(s[p].multiply(s[p]));
        return ans.shiftLeft(1).add(s[n*n].multiply(s[n*n]));
    }

    public static void main(String[] args) {
        for(int n = 0;; n++) {
            System.out.println(n + " " + count(n));
        }
    }

}

यह वर्तमान में O (n ^ 4) को लेने के लिए एक गतिशील प्रोग्रामिंग योजना का उपयोग करता है, ताकि pएक रंग के वर्गों पर प्यादों को रखने के तरीकों की गणना की जा सके 0 <= p <= n^2। मुझे लगता है कि इसे और अधिक कुशलता से करना संभव होना चाहिए।

परिणाम यहाँ देखें।

व्याख्या

एक वैध समाधान में, हर कॉलम में सबसे निचले सफेद मोहरे इस तरह से एक ज़िगज़ैगिंग लाइन बनाते हैं:

प्यादा रेखा

यही है, कॉलम c में लाइन की ऊंचाई कॉलम c - 1 में अपनी स्थिति से +/- 1 होनी चाहिए । लाइन बोर्ड के ऊपर दो काल्पनिक पंक्तियों पर भी जा सकती है।

हम पहले पर एक पंक्ति आकर्षित करने के लिए तरीके की संख्या को खोजने के लिए गतिशील प्रोग्रामिंग का उपयोग कर सकते स्तंभों को शामिल पी , उन स्तंभों पर प्यादे ऊंचाई पर है पर वें स्तंभ, स्तंभ के लिए परिणामों का उपयोग ग - 1 , ऊंचाई ज + / - 1 , और पंजे की संख्या p - h


क्या आप n = 87 के लिए नंबर साझा कर सकते हैं? या कम से कम परिमाण का क्रम? यह एक बहुत बड़ी संख्या है ...
रेटो कोराडी

मैं थोड़ा उलझन में हूँ कि आप यहाँ क्या कर रहे हैं, लेकिन यह बहुत प्रभावशाली है!
सेमीक्सू

मुझे लगता है कि मुझे आपके स्पष्टीकरण के अधिकांश मिलते हैं, जब आप कहते हैं कि "लाइन बोर्ड के ऊपर दो काल्पनिक पंक्तियों पर भी जा सकती है"
cmxu

@ चेंजिंग, इसका मतलब केवल यह है कि उस कॉलम में कोई प्यादे नहीं हैं।
feersum

@ फैर्सम मैं देखता हूं कि यह अधिक समझ में आता है, मैं यह देखने जा रहा हूं कि क्या मैं तर्क के माध्यम से काम कर सकता हूं और देख सकता हूं कि क्या मुझे इसे और भी तेजी से लागू करने का कोई तरीका मिल सकता है।
सेमीक्सू

5

जावा

वर्तमान में, मेरा कोड बहुत लंबा और थकाऊ है, मैं इसे और तेज़ बनाने पर काम कर रहा हूँ। मूल्यों को खोजने के लिए मैं एक पुनरावर्ती विधि का उपयोग करता हूं। यह 2 या 3 सेकंड के भीतर पहले 5 की गणना करता है, लेकिन यह बाद में बहुत धीमा हो जाता है। इसके अलावा, अगर नंबर सही हैं, तो मुझे अभी तक यकीन नहीं है, लेकिन पहले कुछ टिप्पणी के साथ लाइन में लगते हैं। किसी भी सुझाव का स्वागत है।

उत्पादन

2x2:    3
4x4:    30
6x6:    410
8x8:    6148
10x10:  96120

व्याख्या

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

कोड

public class Chess {
    public static void main(String[] args){
        System.out.println(solve(1));
        System.out.println(solve(2));
        System.out.println(solve(3));
        System.out.println(solve(4));
        System.out.println(solve(5));
    }
    static int solve(int n){
        int m =2*n;
        int[][] b = new int[m][m];
        for(int i = 0; i < m; i++){
            for(int j = 0; j < m; j++){
                b[i][j]=0;
            }
        }
        return count(m,m*m,m*m/2,m*m/2,0,b);
    }
    static int count(int n,int sqLeft, int bLeft, int wLeft, int count, int[][] b){
        if(sqLeft == 0){
            /*for(int i = 0; i < n; i++){
                for(int j = 0; j < n; j++){
                    System.out.print(b[i][j]);
                }
                System.out.println();
            }
            System.out.println();*/
            return count+1;
        }
        int x=(sqLeft-1)%n;
        int y=(sqLeft-1)/n;
        if(wLeft==0){
            if(y!=0){
                if ((x==0?true:b[x-1][y-1]!=1)&&(x==n-1?true:b[x+1][y-1]!= 1)) {
                    b[x][y] = 2;
                    return count(n, sqLeft-1, bLeft-1, wLeft, count, b);
                } else {
                    return 0;
                }
            } else {
                b[x][y]=2;
                return count(n,sqLeft-1,bLeft-1,wLeft,count,b);
            }
        } else if(bLeft==0){
            if(y!=n-1){
                if((x==0?true:b[x-1][y+1]!=2)&&(x==n-1?true:b[x+1][y+1]!=2)){
                    b[x][y]=1;
                    return count(n,sqLeft-1,bLeft,wLeft-1,count,b);
                } else {
                    return 0;
                }
            } else {
                b[x][y]=1;
                return count(n,sqLeft-1,bLeft,wLeft-1,count,b);
            }
        } else{
            if(y==0){
                if((x==0?true:b[x-1][y+1]!=2)&&(x==n-1?true:b[x+1][y+1]!=2)){
                    int[][] c=new int[n][n];
                    for(int i = 0; i < n; i++){
                        System.arraycopy(b[i], 0, c[i], 0, n);
                    }
                    b[x][y]=2;
                    c[x][y]=1;
                    return count(n,sqLeft-1,bLeft,wLeft-1,count,c)+count(n,sqLeft-1,bLeft-1,wLeft,count,b);
                } else {
                    b[x][y]=2;
                    return count(n,sqLeft-1,bLeft-1,wLeft,count,b);
                }
            }else if(y==n-1){
                if((x==0?true:b[x-1][y-1]!=1)&&(x==n-1?true:b[x+1][y-1]!=1)){
                    int[][] c=new int[n][n];
                    for(int i = 0; i < n; i++){
                        System.arraycopy(b[i], 0, c[i], 0, n);
                    }
                    b[x][y]=2;
                    c[x][y]=1;
                    return count(n,sqLeft-1,bLeft,wLeft-1,count,c)+count(n,sqLeft-1,bLeft-1,wLeft,count,b);
                } else {
                    b[x][y]=1;
                    return count(n,sqLeft-1,bLeft,wLeft-1,count,b);
                }
            }else{
                if(((x==0?true:b[x-1][y-1]!=1)&&(x==n-1?true:b[x+1][y-1]!=1))&&((x==0?true:b[x-1][y+1]!=2)&&(x==n-1?true:b[x+1][y+1]!=2))){
                    int[][] c=new int[n][n];
                    for(int i = 0; i < n; i++){
                        System.arraycopy(b[i], 0, c[i], 0, n);
                    }
                    b[x][y]=2;
                    c[x][y]=1;
                    return count(n,sqLeft-1,bLeft,wLeft-1,count,c)+count(n,sqLeft-1,bLeft-1,wLeft,count,b);
                } else if ((x==0?true:b[x-1][y-1]!=1)&&(x==n-1?true:b[x+1][y-1]!=1)){
                    b[x][y]=2;
                    return count(n,sqLeft-1,bLeft-1,wLeft,count,b);
                } else if ((x==0?true:b[x-1][y+1]!=2)&&(x==n-1?true:b[x+1][y+1]!=2)){
                    b[x][y]=1;
                    return count(n,sqLeft-1,bLeft,wLeft-1,count,b);
                } else {
                    return 0;
                }
            }
        }
    }
}

इसे यहाँ आज़माएँ (Ideone के लिए तेज़ी से नहीं चलेगा इसलिए अंतिम मूल्य प्रिंट नहीं करता है, ऐसा लगता है कि मेरा समाधान बहुत अच्छा नहीं है!)


मैं ६१४ 6 तक पहुँचता हूं, और मैंने अभी तक इससे परे कोई मूल्य नहीं बनाया है।
पीटर टेलर

@PeterTaylor वेल एग्निश ने कहा कि यह 3, 28, 408 होना चाहिए, इसलिए मुझे संदेह है कि 6148 सही है। मुझे आश्चर्य है कि हम दोनों क्या गलत कर रहे हैं?
cmxu

काफी तेज तो मेरा। +1 भले ही मैं परिणामों पर सहमत न हो
edc65

नमस्कार! मैंने कभी नहीं कहा कि यह 28, 408 सही क्रम 3,30,410 है, ...
अग्निपोम चट्टोपाध्याय

आपने कहा, @ edc65 में सही मूल्य थे, और उनके मूल्य 28, 408 हैं?
15x15 बजे cmxu

4

सी ++ के साथ pthreads, n = 147 156

नवीनतम परिणाम एक बीफ़ियर मशीन पर पहले जैसा ही कोड चलाने से है। यह अब क्वाड-कोर i7 (कोर i7-4770) के साथ एक डेस्कटॉप पर चलाया गया था, जो 120 सेकंड में n = 156 हो गया। परिणाम है:

7858103688882482349696225090648142317093426691269441606893544257091315906431773702676266198643058148987365151560565922891852481847049321541347582728793175114543840164406674137410614843200

यह एक गतिशील प्रोग्रामिंग एल्गोरिथ्म का उपयोग कर रहा है। मैंने शुरुआत में दृष्टिकोण की ओर इशारा किया, जहां परिणाम पंक्ति द्वारा पंक्तिबद्ध किया जाएगा, लेकिन मैं कभी भी राज्य के एक टन को ट्रैक किए बिना समाधान का विस्तार करने के तरीके के साथ नहीं आ सकता।

एक महत्वपूर्ण कुशल समाधान को सक्षम करने वाले प्रमुख अंतर्दृष्टि थे:

  • चूंकि काले वर्गों पर प्यादे केवल अन्य काले वर्गों पर प्यादों पर हमला कर सकते हैं, और सफेद वर्गों के लिए भी यही सच है, काले और सफेद वर्ग स्वतंत्र हैं, और इन्हें अलग से संसाधित किया जा सकता है। और चूंकि वे समान हैं, हमें केवल दो में से एक को संसाधित करने की आवश्यकता है।
  • विकर्ण द्वारा बोर्ड विकर्ण को संसाधित करते समय समस्या बहुत आसान हो जाती है।

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

इसलिए, प्रत्येक विकर्ण के लिए ट्रैक किया गया राज्य प्रत्येक संयोजन के लिए मान्य मोहरा विन्यास की संख्या है:

  • पंक्ति में काले प्यादों की संख्या (या दूसरे शब्दों में, विकर्ण के भीतर की स्थिति जो श्वेत प्यादों को सफेद प्यादों से अलग करती है)।
  • काले प्यादे की कुल गिनती। हमें प्रति मोहरे की गिनती में पूरी बात को ट्रैक करने की आवश्यकता है क्योंकि हमें केवल काले पंजे और सफेद पंजे की समान संख्या की आवश्यकता है। विकर्णों को संसाधित करते समय, गिनती भिन्न हो सकती है, और फिर भी अंत में वैध समाधान हो सकते हैं।

जब एक विकर्ण से अगले एक तक कदम रखते हैं, तो वैध समाधानों का निर्माण करने के लिए एक और बाधा होती है: सफेद मोतियों से काले मोहरे को अलग करने वाली स्थिति में वृद्धि नहीं हो सकती है। तो मान्य विन्यासों की संख्या की गणना पिछले विकर्ण के मान्य विन्यासों के योग के रूप में की जाती है जो समान या बड़े होते हैं।

मूल डीपी कदम तब बहुत सरल है। एक विकर्ण में प्रत्येक मान पिछले विकर्ण से मानों का एक योग है। केवल कुछ हद तक दर्दनाक हिस्सा सूचकांकों और लूप पर्वतमाला की सही गणना कर रहा है। चूंकि हम विकर्णों पर काम कर रहे हैं, गणना की पहली छमाही के दौरान लंबाई बढ़ जाती है, और दूसरी छमाही के लिए घट जाती है, जिससे लूप की गणना अधिक बोझिल हो जाती है। बोर्ड की सीमा पर मूल्यों के लिए कुछ विचार भी हैं, क्योंकि वे केवल एक तरफ विकर्ण पड़ोसी होते हैं जब विकर्ण से विकर्ण की ओर बढ़ते हैं।

उपयोग की जाने वाली मेमोरी की मात्रा O (n ^ 3) है। मैं राज्य डेटा की दो प्रतियां रखता हूं, और उनके बीच पिंग पोंग। मेरा मानना ​​है कि राज्य डेटा के एकल उदाहरण के साथ काम करना संभव होगा। लेकिन आपको बहुत सावधान रहना होगा कि पुराने मूल्यों को पूरी तरह से भस्म होने से पहले कोई मूल्य अपडेट नहीं किया जाता है। इसके अलावा, यह मेरे द्वारा शुरू की गई समानांतर प्रसंस्करण के लिए अच्छी तरह से काम नहीं करेगा।

रनटाइम जटिलता है ... बहुपद। एल्गोरिथ्म में 4 नेस्टेड लूप हैं, इसलिए पहली नजर में यह O (n ^ 4) जैसा दिखेगा। लेकिन आपको स्पष्ट रूप से इन आकारों में बड़े चिह्नों की आवश्यकता है, और संख्याएँ स्वयं भी बड़े आकारों में लंबी हो जाती हैं। परिणाम में अंकों की संख्या लगभग आनुपातिक रूप से n तक बढ़ जाती है, जिससे पूरी बात O (n ^ 5) हो जाएगी। दूसरी ओर, मुझे कुछ प्रदर्शन में सुधार मिला, जो सभी छोरों की पूरी श्रृंखला से गुजरने से बचता है।

तो जबकि यह अभी भी एक काफी महंगा एल्गोरिथ्म है, यह समाधानों की गणना करने वाले एल्गोरिदम की तुलना में बहुत दूर है, जो सभी घातीय हैं।

कार्यान्वयन पर कुछ नोट्स:

  • जबकि काले वर्गों पर 2 * n ^ 2 काले पंजे तक हो सकते हैं, मैं केवल n ^ 2 काले पंजे तक कॉन्फ़िगरेशन संख्याओं की गणना करता हूं। चूंकि काले और सफेद प्यादों के बीच समरूपता है, k और 2 * n ^ 2-k के लिए कॉन्फ़िगरेशन संख्या समान हैं।
  • समान समरूपता के आधार पर काले वर्गों पर विन्यास की गणना से समाधान की संख्या की गणना की जाती है। समाधानों की कुल संख्या (जिसमें प्रत्येक रंग के 2 * n ^ 2 pawns होने की आवश्यकता होती है) k के काले प्यादों के लिए विन्यास की संख्या है जो 2 * n-2-k के काले प्यादों के लिए विन्यास की संख्या से गुणा किए गए वर्गों के एक रंग पर होती है। वर्गों के दूसरे रंग पर, सभी k पर अभिव्यक्त।
  • केवल विकर्ण स्थिति और प्यादा गणना के लिए कॉन्फ़िगरेशन काउंटिंग को संग्रहीत करने के अलावा, मैं प्यादा गणना की श्रेणी भी रखता हूं, जिसमें प्रति स्थिति मान्य कॉन्फ़िगरेशन हैं। यह आंतरिक लूप की सीमा को काफी हद तक काटने की अनुमति देता है। इसके बिना, मैंने पाया कि बहुत सारे शून्य जोड़े जा रहे थे। मुझे इससे बहुत अच्छा प्रदर्शन मिला।
  • एल्गोरिथ्म काफी अच्छी तरह से समानांतर करता है, विशेष रूप से बड़े आकारों में। विकर्णों को क्रमिक रूप से प्रक्रियाएं करनी होती हैं, इसलिए प्रत्येक विकर्ण के अंत में एक अवरोध होता है। लेकिन विकर्ण के भीतर की स्थितियों को समानांतर में संसाधित किया जा सकता है।
  • प्रोफाइलिंग से पता चलता है कि अड़चन स्पष्ट रूप से बिगिन्ट वैल्यूज को जोड़ने में है। मैंने कोड के कुछ रूपों के साथ खेला, लेकिन यह बहुत अधिक अनुकूलित नहीं है। मुझे संदेह है कि इनलाइन असेंबली से ले जाने के साथ 64-बिट परिवर्धन का उपयोग करने में एक महत्वपूर्ण सुधार हो सकता है।

मुख्य एल्गोरिथ्म कोड। THREADSउपयोग किए जाने वाले थ्रेड्स की संख्या को नियंत्रित करता है, जहां सीपीयू कोर की संख्या एक उचित प्रारंभिक बिंदु होनी चाहिए:

#ifndef THREADS
#define THREADS 2
#endif

#if THREADS > 1
#include <pthread.h>
#endif

#include <vector>
#include <iostream>
#include <sstream>

#include "BigUint.h"

typedef std::vector<BigUint> BigUintVec;
typedef std::vector<int> IntVec;

static int N;
static int NPawn;
static int NPos;

static BigUintVec PawnC[2];
static IntVec PawnMinC[2];
static IntVec PawnMaxC[2];

#if THREADS > 1
static pthread_mutex_t ThreadMutex;
static pthread_cond_t ThreadCond;
static int BarrierCount;
#endif

#if THREADS > 1
static void ThreadBarrier()
{
    pthread_mutex_lock(&ThreadMutex);

    --BarrierCount;
    if (BarrierCount)
    {
        pthread_cond_wait(&ThreadCond, &ThreadMutex);
    }
    else
    {
        pthread_cond_broadcast(&ThreadCond);
        BarrierCount = THREADS;
    }

    pthread_mutex_unlock(&ThreadMutex);
}
#endif

static void* countThread(void* pData)
{
    int* pThreadIdx = static_cast<int*>(pData);
    int threadIdx = *pThreadIdx;

    int prevDiagMin = N - 1;
    int prevDiagMax = N;

    for (int iDiag = 1; iDiag < 2 * N; ++iDiag)
    {
        BigUintVec& rSrcC = PawnC[1 - iDiag % 2];
        BigUintVec& rDstC = PawnC[iDiag % 2];

        IntVec& rSrcMinC = PawnMinC[1 - iDiag % 2];
        IntVec& rDstMinC = PawnMinC[iDiag % 2];

        IntVec& rSrcMaxC = PawnMaxC[1 - iDiag % 2];
        IntVec& rDstMaxC = PawnMaxC[iDiag % 2];

        int diagMin = prevDiagMin;
        int diagMax = prevDiagMax;;
        if (iDiag < N)
        {
            --diagMin;
            ++diagMax;
        }
        else if (iDiag > N)
        {
            ++diagMin;
            --diagMax;
        }

        int iLastPos = diagMax;
        if (prevDiagMax < diagMax)
        {
            iLastPos = prevDiagMax;
        }

        for (int iPos = diagMin + threadIdx; iPos <= iLastPos; iPos += THREADS)
        {
            int nAdd = iPos - diagMin;

            for (int iPawn = nAdd; iPawn < NPawn; ++iPawn)
            {
                rDstC[iPos * NPawn + iPawn] = 0;
            }

            rDstMinC[iPos] = NPawn;
            rDstMaxC[iPos] = -1;

            int iFirstPrevPos = iPos;
            if (!nAdd)
            {
                iFirstPrevPos = prevDiagMin;
            }

            for (int iPrevPos = iFirstPrevPos;
                 iPrevPos <= prevDiagMax; ++iPrevPos)
            {
                int iLastPawn = rSrcMaxC[iPrevPos];
                if (iLastPawn + nAdd >= NPawn)
                {
                    iLastPawn = NPawn - 1 - nAdd;
                }

                if (rSrcMinC[iPrevPos] > iLastPawn)
                {
                    continue;
                }

                if (rSrcMinC[iPrevPos] < rDstMinC[iPos])
                {
                    rDstMinC[iPos] = rSrcMinC[iPrevPos];
                }

                if (iLastPawn > rDstMaxC[iPos])
                {
                    rDstMaxC[iPos] = iLastPawn;
                }

                for (int iPawn = rSrcMinC[iPrevPos];
                     iPawn <= iLastPawn; ++iPawn)
                {
                    rDstC[iPos * NPawn + iPawn + nAdd] += rSrcC[iPrevPos * NPawn + iPawn];
                }
            }

            if (rDstMinC[iPos] <= rDstMaxC[iPos])
            {
                rDstMinC[iPos] += nAdd;
                rDstMaxC[iPos] += nAdd;
            }
        }

        if (threadIdx == THREADS - 1 && diagMax > prevDiagMax)
        {
            int pawnFull = (iDiag + 1) * (iDiag + 1);
            rDstC[diagMax * NPawn + pawnFull] = 1;
            rDstMinC[diagMax] = pawnFull;
            rDstMaxC[diagMax] = pawnFull;
        }

        prevDiagMin = diagMin;
        prevDiagMax = diagMax;

#if THREADS > 1
        ThreadBarrier();
#endif
    }

    return 0;
}

static void countPawns(BigUint& rRes)
{
    NPawn = N * N + 1;
    NPos = 2 * N;

    PawnC[0].resize(NPos * NPawn);
    PawnC[1].resize(NPos * NPawn);

    PawnMinC[0].assign(NPos, NPawn);
    PawnMinC[1].assign(NPos, NPawn);

    PawnMaxC[0].assign(NPos, -1);
    PawnMaxC[1].assign(NPos, -1);

    PawnC[0][(N - 1) * NPawn + 0] = 1;
    PawnMinC[0][N - 1] = 0;
    PawnMaxC[0][N - 1] = 0;

    PawnC[0][N * NPawn + 1] = 1;
    PawnMinC[0][N] = 1;
    PawnMaxC[0][N] = 1;

#if THREADS > 1
    pthread_mutex_init(&ThreadMutex, 0);
    pthread_cond_init(&ThreadCond, 0);

    BarrierCount = THREADS;

    int threadIdxA[THREADS] = {0};
    pthread_t threadA[THREADS] = {0};
    for (int iThread = 0; iThread < THREADS; ++iThread)
    {
        threadIdxA[iThread] = iThread;
        pthread_create(threadA + iThread, 0, countThread, threadIdxA + iThread);
    }

    for (int iThread = 0; iThread < THREADS; ++iThread)
    {
        pthread_join(threadA[iThread], 0);
    }

    pthread_cond_destroy(&ThreadCond);
    pthread_mutex_destroy(&ThreadMutex);
#else
    int threadIdx = 0;
    countThread(&threadIdx);
#endif

    BigUint solCount;
    BigUintVec& rResC = PawnC[1];
    for (int iPawn = 0; iPawn < NPawn; ++iPawn)
    {
        BigUint nComb = rResC[(N - 1) * NPawn + iPawn];

        nComb *= nComb;
        if (iPawn < NPawn - 1)
        {
            nComb *= 2;
        }

        solCount += nComb;
    }

    std::string solStr;
    solCount.toDecString(solStr);
    std::cout << solStr << std::endl;
}

int main(int argc, char* argv[])
{
    std::istringstream strm(argv[1]);
    strm >> N;

    BigUint res;
    countPawns(res);

    return 0;
}

इसके लिए एक बड़े वर्ग की जरूरत है जो मैंने इस उद्देश्य के लिए लिखा था। ध्यान दें कि यह सामान्य उद्देश्य नहीं है bigint वर्ग। यह इस विशिष्ट एल्गोरिथ्म द्वारा उपयोग किए गए कार्यों का समर्थन करने के लिए पर्याप्त है:

#ifndef BIG_UINT_H
#define BIG_UINT_H

#include <cstdint>
#include <string>
#include <vector>

class BigUint
{
public:
    BigUint()
      : m_size(1),
        m_cap(MIN_CAP),
        m_valA(m_fixedValA)
    {
        m_valA[0] = 0;
    }

    BigUint(uint32_t val)
      : m_size(1),
        m_cap(MIN_CAP),
        m_valA(m_fixedValA)
    {
        m_valA[0] = val;
    }

    BigUint(const BigUint& rhs)
      : m_size(rhs.m_size),
        m_cap(MIN_CAP),
        m_valA(m_fixedValA)
    {
        if (m_size > MIN_CAP)
        {
            m_cap = m_size;
            m_valA = new uint32_t[m_cap];
        }

        for (int iVal = 0; iVal < m_size; ++iVal)
        {
            m_valA[iVal] = rhs.m_valA[iVal];
        }
    }

    ~BigUint()
    {
        if (m_cap > MIN_CAP)
        {
            delete[] m_valA;
        }
    }

    BigUint& operator=(uint32_t val)
    {
        m_size = 1;
        m_valA[0] = val;

        return *this;
    }

    BigUint& operator=(const BigUint& rhs)
    {
        if (rhs.m_size > m_cap)
        {
            if (m_cap > MIN_CAP)
            {
                delete[] m_valA;
            }

            m_cap = rhs.m_size;
            m_valA = new uint32_t[m_cap];
        }

        m_size = rhs.m_size;

        for (int iVal = 0; iVal < m_size; ++iVal)
        {
            m_valA[iVal] = rhs.m_valA[iVal];
        }

        return *this;
    }

    BigUint& operator+=(const BigUint& rhs)
    {
        if (rhs.m_size > m_size)
        {
            resize(rhs.m_size);
        }

        uint64_t sum = 0;
        for (int iVal = 0; iVal < m_size; ++iVal)
        {
            sum += m_valA[iVal];
            if (iVal < rhs.m_size)
            {
                sum += rhs.m_valA[iVal];
            }
            m_valA[iVal] = sum;
            sum >>= 32u;
        }

        if (sum)
        {
            resize(m_size + 1);
            m_valA[m_size - 1] = sum;
        }

        return *this;
    }

    BigUint& operator*=(const BigUint& rhs)
    {
        int resSize = m_size + rhs.m_size - 1;
        uint32_t* resValA = new uint32_t[resSize];

        uint64_t sum = 0;

        for (int iResVal = 0; iResVal < resSize; ++iResVal)
        {
            uint64_t carry = 0;

            for (int iLhsVal = 0;
                 iLhsVal <= iResVal && iLhsVal < m_size; ++iLhsVal)
            {
                int iRhsVal = iResVal - iLhsVal;
                if (iRhsVal < rhs.m_size)
                {
                    uint64_t prod = m_valA[iLhsVal];
                    prod *= rhs.m_valA[iRhsVal];
                    uint64_t newSum = sum + prod;
                    if (newSum < sum)
                    {
                        ++carry;
                    }
                    sum = newSum;
                }
            }

            resValA[iResVal] = sum & UINT64_C(0xFFFFFFFF);
            sum >>= 32u;
            sum += carry << 32u;
        }

        if (resSize > m_cap)
        {
            if (m_cap > MIN_CAP)
            {
                delete[] m_valA;
            }

            m_cap = resSize;
            m_valA = resValA;
        }
        else
        {
            for (int iVal = 0; iVal < resSize; ++iVal)
            {
                m_valA[iVal] = resValA[iVal];
            }

            delete[] resValA;
        }

        m_size = resSize;

        if (sum)
        {
            resize(m_size + 1);
            m_valA[m_size - 1] = sum;
        }

        return *this;
    }

    void divMod(uint32_t rhs, uint32_t& rMod)
    {
        uint64_t div = 0;
        for (int iVal = m_size - 1; iVal >= 0; --iVal)
        {
            div <<= 32u;
            div += m_valA[iVal];

            uint64_t val = div / rhs;
            div -= val * rhs;

            if (val || iVal == 0 || iVal < m_size - 1)
            {
                m_valA[iVal] = val;
            }
            else
            {
                --m_size;
            }
        }

        rMod = div;
    }

    void toDecString(std::string& rStr) const
    {
        std::vector<char> digits;

        BigUint rem(*this);
        while (rem.m_size > 1 || rem.m_valA[0])
        {
            uint32_t digit = 0;
            rem.divMod(10, digit);
            digits.push_back(digit);
        }

        if (digits.empty())
        {
            rStr = "0";
        }
        else
        {
            rStr.clear();
            rStr.reserve(digits.size());

            for (int iDigit = digits.size() - 1; iDigit >= 0; --iDigit)
            {
                rStr.append(1, '0' + digits[iDigit]);
            }
        }
    }

private:
    static const int MIN_CAP = 8;

    void resize(int newSize)
    {
        if (newSize > m_cap)
        {
            uint32_t* newValA = new uint32_t[newSize];

            for (int iVal = 0; iVal < m_size; ++iVal)
            {
                newValA[iVal] = m_valA[iVal];
            }

            if (m_cap > MIN_CAP)
            {
                delete[] m_valA;
            }

            m_cap = newSize;
            m_valA = newValA;
        }

        for (int iVal = m_size; iVal < newSize; ++iVal)
        {
            m_valA[iVal] = 0;
        }

        m_size = newSize;
    }

    int m_size;
    int m_cap;

    uint32_t* m_valA;
    uint32_t m_fixedValA[MIN_CAP];
};

#endif // BIG_UINT_H

0

Fantom

यहाँ एक प्रारंभिक पोस्ट है जो रूपरेखा तैयार करता है। मुझे लगता है कि प्रक्रिया अपेक्षाकृत अच्छी है, लेकिन कार्यान्वयन अभी एक तरह से बेकार है। मुझे संभवतः गणना की संख्या को कम करने की कोशिश करनी चाहिए जो मैं कर रहा हूं, और इसके बजाय बस अधिक स्थिरांक पास करें।

रणनीति

मूल रूप से, प्रत्येक सफेद मोहरे को अन्य सफेद मोतियों पर हमला करना चाहिए। इसलिए मैं एक सफेद मोहरा रखकर शुरू करता हूं, प्रत्येक जगह पर प्यादे रखकर हमला करता है, और अनिवार्य रूप से सभी स्थानों पर सफेद मोहरे के साथ बोर्ड में भरना होता है। अगर मैंने बहुत सारे सफेद पंजे पहले ही जोड़ लिए हैं तो मैं रुक जाता हूं। यदि, इसके अंत में, मेरे पास ठीक 2n ^ 2 प्यादे हैं, तो यह एक समाधान है। यदि इससे कम है, तो कहीं और एक सफेद मोहरा जोड़ें, उसके सभी आवश्यक स्थानों को भरें, और फिर से गिनें। मैं हर बार 2n ^ 2 से कम के साथ एक भरण को पुन: विभाजित करता हूं, और अंतिम प्यादा के साथ और उसके बिना समाधानों की संख्या की गणना करता हूं।

कोड

class main
{
  public  Void main(){

    echo(calculate(1))
    echo(calculate(2))
    echo(calculate(3))
    echo(calculate(4))
    echo(calculate(5))

  }

  public static  Int calculate(Int n){

    n *= 2
    //Initialize the array -  Definitely a weakpoint, but only runs once
    Bool[][] white := [,]
    n.times{ 
      row := [,]
      n.times{ row.add(false) }
      white.add(row)
    }

    return recurse(white, -1, 0, n, n*n/2)
  }

  private static  Int recurse(Bool[][] white, Int lastPlacement, Int numWhites, Int n, Int totalWhite){
    if(totalWhite - numWhites > n*n - 1 - lastPlacement) return 0
    lastPlacement++
    Int row := lastPlacement / n
    Int col := lastPlacement % n
    if(white[row][col]){ return recurse(white, lastPlacement, numWhites, n, totalWhite)}
    Bool[][] whiteCopy := copy(white)
    whiteCopy[row][col] = true
    Int result := fillIn(whiteCopy, numWhites + 1, totalWhite)
    if(result == -1){
      return recurse(white, lastPlacement, numWhites,n, totalWhite);
    }
    else if(result == totalWhite){
      //echo("Found solution")
      //echo("WhiteCopy = $whiteCopy")
      return recurse(white, lastPlacement, numWhites,n, totalWhite) + 1;
    }
    else return recurse(whiteCopy, lastPlacement, result,n, totalWhite) + recurse(white, lastPlacement, numWhites,n, totalWhite)


  }

  //Every white must be attacking other whites, so fill in the grid with all necessary points
  //Stop if number of whites used goes too high
  private static Int fillIn(Bool[][] white, Int count, Int n){
    white[0..-2].eachWhile |Bool[] row, Int rowIndex -> Bool?| {
      return row.eachWhile |Bool isWhite, Int colIndex -> Bool?|{
        if(isWhite){
          //Catching index out of bounds is faster than checking index every time
          try{
            if(colIndex > 0 && !white[rowIndex + 1][colIndex - 1]){
              white[rowIndex + 1][colIndex - 1] = true
              count++
            }
            if(!white[rowIndex + 1][colIndex + 1]){
              white[rowIndex + 1][colIndex + 1] = true
              count++
            }
          } catch {}
        }
        if(count > n){ count = -1; return true}
        return null
      }//End row.each
    }//End white.each
    return count
  }

  private static Bool[][] copy(Bool[][] orig){
    Bool[][] copy := [,]
    orig.each{
      copy.add(it.dup)
    }
    return copy
  }

}

उत्पादन

केवल इसे अभी 5 के लिए बनाता है, लेकिन मुझे लगता है कि अधिकांश मुद्दा कार्यान्वयन में है।

3
30
410
6148
96120

परीक्षा


यह मेरी रणनीति भी है, लेकिन यहाँ पोस्ट किए गए अन्य समाधानों की तुलना में बहुत धीमी गति से लगता है।
edc65

@ edc65 समाधानों की गणना करने वाले दृष्टिकोण को मौका नहीं मिलेगा। यदि कोई संदेह था, तो feersum के एल्गोरिदम द्वारा निर्मित सरासर संख्या इसका प्रमाण है। कुछ प्रकार के गतिशील प्रोग्रामिंग एल्गोरिदम जो उन्हें गणना किए बिना समाधानों की संख्या की गणना करते हैं, यहां जाने का तरीका है।
रेटो कोराडी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.