দাবা বোর্ডে অনেকগুলি পাউন্ড


10

একটি পূর্ণসংখ্যা 2n দেওয়া, সম্ভাব্য উপায়গুলির 2 সন্ধান করুন যাতে 2n 2 টু দাবা বোর্ডে 2n ^ 2 কালো প্যাঁক এবং 2n ^ 2 সাদা প্যাঁকাগুলি এমনভাবে সাজানো যেতে পারে যাতে কোনও प्याদ অন্যটিতে আক্রমণ না করে।

  • একটি কালো প্যাঁচ কেবল একটি সাদা পদ্দা আক্রমণ করতে পারে, এবং বিপরীতে।
  • আক্রমণ করার স্বাভাবিক দাবা বিধিগুলি, অর্থাত্ সাদা প্যাঁচগুলি তত্ক্ষণাত্ ত্রিভুজভাবে স্কোয়ারের সামনে আক্রমণ করে এবং কালো প্যাঁচগুলি আক্রমণকারী স্কোয়ারগুলি তাত্ক্ষণিকভাবে পিছনে পিছনে পড়ে থাকে (সাদা পর্যবেক্ষকের দ্বারা দেখা হিসাবে)।
  • সমস্ত ঘূর্ণন, প্রতিচ্ছবি পৃথক হিসাবে গণনা।

প্রোগ্রাম যা 120 সেকেন্ডের মধ্যে 2n সর্বোচ্চ মানের জন্য সমস্ত সম্ভাব্য কনফিগারেশন আউটপুট করতে পারে। (যদিও সমস্ত প্রোগ্রাম স্বাগত জানানো হয়)

উদাহরণস্বরূপ, অ্যালিসের প্রোগ্রামটি 120 সেকেন্ডের মধ্যে এন = 16 পর্যন্ত ডিল করতে পারে এবং বব একই সময়ের মধ্যে এন = 20 পর্যন্ত ডিল করতে পারে। বব জিতল।

প্ল্যাটফর্ম: লিনাক্স 2.7GHz @ 4 সিপিইউ


2
আউটপুট ফর্ম্যাট কি?
ডোরকনবব

2
পরীক্ষার জন্য: কেউ জড়িত নম্বর সম্পর্কে কোন ধারণা আছে? আমি 2x2 3 সমাধান এবং জন্য 4x4 28 সমাধান পাওয়া
edc65

1
@ এডসি 65, আমি এটি 3, 30, 410 তৈরি করেছি I've আমি বিকল্প পদ্ধতিতে 3 এবং 30 টি পরীক্ষা করেছি।
পিটার টেলর

1
আমার কোডটি প্রথম কয়েকটি উত্পন্ন করেছে: 3, 30, 410, 6148, 96120, 1526700. যদিও, আমার কাছে চেক করার কোনও উপায় নেই। কেউ কি একই পাবেন?
সেমিxসু

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));
        }
    }

}

এটি বর্তমানে pএকটি রঙের স্কোয়ারের উপর জঞ্জাল রাখার উপায়গুলি গণনা করতে O (n ^ 4) ক্রিয়াকলাপ গ্রহণ করে একটি গতিশীল প্রোগ্রামিং স্কিম ব্যবহার করে 0 <= p <= n^2। আমি মনে করি এটি আরও বেশি দক্ষতার সাথে করা সম্ভব হবে।

এখানে ফলাফল দেখুন।

ব্যাখ্যা

একটি বৈধ সমাধানে, প্রতিটি কলামের সর্বনিম্ন সাদা পদ্মাগুলি অবশ্যই একটি জিগজ্যাগিং লাইন তৈরি করতে হবে:

পদ্মার লাইন

অর্থাৎ, কলাম সি-তে রেখার উচ্চতা তার কলাম গ - 1 এর অবস্থান থেকে +/- 1 হতে হবে । লাইনটি বোর্ডের শীর্ষে দুটি কাল্পনিক সারিতেও যেতে পারে।

আমরা প্রথম একটি লাইন আঁকতে উপায়ে সংখ্যা খুঁজে বের করতে গতিশীল প্রোগ্রামিং ব্যবহার করতে পারেন কলাম যে অন্তর্ভুক্ত পি , যারা কলাম উপর দাবার গুটির উচ্চতা এ উপর ম কলাম, কলামের জন্য ফলাফল ব্যবহার গ - 1 , উচ্চতা H + / - 1 , এবং प्याদ সংখ্যা পি - এইচ


আপনি কি এন = 87 এর জন্য নম্বরটি ভাগ করতে পারবেন? না কি কমপক্ষে ক্রম? এটি একটি খুব বড় সংখ্যক হতে হবে ...
রেটো কোরাাদি

আপনি এখানে যা করছেন তা সম্পর্কে আমি কিছুটা বিভ্রান্ত, তবে এটি খুব চিত্তাকর্ষক!
সেএমএক্সসু

আমি মনে করি আমি আপনার বেশিরভাগ ব্যাখ্যা পেয়েছি, আপনি যখন বলবেন ব্যতীত "লাইনটি বোর্ডের উপরের উপরে দুটি কাল্পনিক সারিগুলিতেও যেতে পারে"
সেএমএক্সু

@ চ্যাঙ্কিং, এর একমাত্র অর্থ হ'ল সেই কলামটিতে কোনও থাবা নেই।
ফেয়ারসুম

@ ফেয়ারসাম আমি দেখতে পেয়েছি এটি আরও অর্থবোধ করে, আমি যুক্তি দিয়ে কাজ করতে পারি কিনা তা দেখতে যাচ্ছি এবং আরও দ্রুততার সাথে এটি প্রয়োগ করার কোনও উপায় খুঁজে পাচ্ছি কিনা তা আমি দেখতে যাচ্ছি।
সেএমএক্সসু

5

জাভা

বর্তমানে, আমার কোডটি অত্যন্ত দীর্ঘ এবং ক্লান্তিকর, আমি এটিকে আরও দ্রুত তৈরি করার জন্য কাজ করছি। আমি মানগুলি খুঁজে পেতে একটি পুনরাবৃত্ত পদ্ধতি ব্যবহার করি। এটি 2 বা 3 সেকেন্ডের মধ্যে প্রথম 5 টি গণনা করে তবে এটি পরে অনেক ধীর হয়ে যায়। এছাড়াও, সংখ্যাগুলি সঠিক কিনা তা সম্পর্কে আমি এখনও নিশ্চিত নই, তবে প্রথম কয়েকটি মন্তব্যগুলির সাথে একত্রে লেগেছে বলে মনে হচ্ছে। কোন পরামর্শ স্বাগত।

আউটপুট

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

ব্যাখ্যা

মূল ধারণাটি পুনরাবৃত্তি। মূলত আপনি একটি শূন্য বোর্ড, সমস্ত জিরো সহ একটি বোর্ড দিয়ে শুরু করুন। পুনরাবৃত্তির পদ্ধতিটি কেবল পরবর্তী অবস্থানে কোনও কালো বা সাদা ভাঁড় স্থাপন করতে পারে কিনা তা পরীক্ষা করে দেখায়, যদি এটি কেবল একটি রঙ রাখতে পারে তবে এটি সেখানে রাখে এবং নিজেই কল করে। যদি এটি উভয় রঙগুলিকে রাখতে পারে তবে এটি নিজেকে দুটি বার কল করে, প্রতিটি রঙের সাথে একটি। প্রতিবার যখন এটি নিজেকে কল করে তখন স্কোয়ারগুলি বামে এবং উপযুক্ত রঙ বামে হ্রাস পায়। এটি যখন পুরো বোর্ডটি পূরণ করবে তখন এটি বর্তমান গণনাটি +1 প্রদান করে If যদি এটি জানতে পারে যে পরবর্তী অবস্থানে কালো বা সাদা ভাঁড় দেওয়ার কোনও উপায় নেই, তবে এটি 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;
                }
            }
        }
    }
}

এখানে চেষ্টা করে দেখুন (আইডিয়নের পক্ষে দ্রুত পর্যায়ে দৌড়াবেন না যাতে শেষ মানটি প্রিন্ট না করে, আমার সমাধানটি খুব ভাল লাগে না বলে মনে হচ্ছে!)


আমি 6148 অবধি সম্মতি জানাই, এবং আমি এর বাইরে এখনও কোনও মান উত্পাদন করতে পারি নি।
পিটার টেলর

@ পিটারটেলর ওয়েল অগ্নিশম বলেছেন যে এটি 3, 28, 408 হওয়া উচিত তাই আমার সন্দেহ হয় 6148 ঠিক আছে। আমি ভাবছি আমরা দুজনেই কী ভুল করছি?
সেমিxসু

বেশ দ্রুত আমার। আমি ফলাফলগুলিতে একমত না হলেও +1
edc65

হ্যালো! আমি কখনই বলিনি যে এটি 28, 408 সঠিক অনুক্রমটি 3,30,410, ...
অগ্নিশোম চট্টোপাধ্যায়

আপনি বলেছেন, @ edc65 এর সঠিক মান ছিল এবং তার মানগুলি 28, 408?
সেমিxসু

4

সি ++ পাইথ্রেড সহ, n = 147 156

সর্বশেষ ফলাফলটি বিফায়ার মেশিনে আগের মতো একই কোড চালানো from এটি এখন একটি কোয়াড-কোর আই 7 (কোর আই 7-4770) দিয়ে একটি ডেস্কটপে চালিত হয়েছিল, যা 120 সেকেন্ডে এন = 156 এ চলে গেছে। ফলাফল হলো:

7858103688882482349696225090648142317093426691269441606893544257091315906431773702676266198643058148987365151560565922891852481847049321541347582728793175114543840164406674137410614843200

এটি একটি গতিশীল প্রোগ্রামিং অ্যালগরিদম ব্যবহার করছে। আমি প্রাথমিকভাবে এমন পন্থাগুলি নিয়ে ভাবছিলাম যেখানে ফলাফলটি সারি সারি তৈরি করা হবে, তবে আমি কোনও টন রাষ্ট্রের সন্ধান ছাড়াই সমাধানটি প্রসারিত করার উপায় নিয়ে আসতে পারিনি।

যুক্তিযুক্ত দক্ষ সমাধান সক্ষম করা মূল অন্তর্দৃষ্টিগুলি হ'ল:

  • যেহেতু কালো স্কোয়ারগুলিতে পদ্মারা কেবলমাত্র অন্যান্য কালো স্কোয়ারগুলিতে পশুর আক্রমণ করতে পারে, এবং এটি সাদা স্কোয়ারগুলির ক্ষেত্রেও সত্য, কালো এবং সাদা স্কোয়ারগুলি স্বাধীন এবং পৃথকভাবে প্রক্রিয়াজাত করা যায়। এবং যেহেতু তারা সমতুল্য, আমাদের কেবল দুটির একটির প্রক্রিয়া করা দরকার।
  • তির্যক দ্বারা বোর্ড তির্যকটি প্রক্রিয়া করার সময় সমস্যাটি আরও সহজ হয়।

আপনি যদি কোনও বৈধ কনফিগারেশনের একটি ত্রিভুজটি দেখেন তবে এটি সর্বদা সাদা প্যাঁচগুলির ক্রমযুক্ত থাকে যার পরে সাদা প্যাঁচগুলির ক্রম থাকে (যেখানে উভয় ক্রমও ফাঁকা হতে পারে)। অন্য কথায়, প্রতিটি তির্যকটি সম্পূর্ণরূপে কালো প্যাঁকের সংখ্যা দ্বারা চিহ্নিত করা যায়।

সুতরাং, প্রতিটি তির্যকের জন্য চিহ্নিত রাষ্ট্রটি এর প্রতিটি সংমিশ্রণের জন্য বৈধ প্যাকেজ কনফিগারেশনের সংখ্যা:

  • সারি সারি কালো প্যাঁদের সংখ্যা (বা অন্য কথায়, তির্যকটির মধ্যে অবস্থান যা সাদা পদ্মাগুলি থেকে কালো প্যাঁচাগুলি পৃথক করে)।
  • ব্যবহৃত কালো পশুর মোট গণনা। প্রতি মোহর গুনতে আমাদের পুরো জিনিসটি ট্র্যাক করতে হবে কারণ আমাদের কেবল শেষ প্রান্তে কালো প্যাঁচা এবং সাদা পশুর সমান সংখ্যক প্রয়োজন। ত্রিভুজগুলি প্রক্রিয়া করার সময়, গণনাগুলি পৃথক হতে পারে এবং এরপরে শেষ পর্যন্ত বৈধ সমাধানের ফলস্বরূপ।

এক তির্যক থেকে পরের দিকে পদক্ষেপ নেওয়ার সময়, বৈধ সমাধান তৈরির জন্য আরও একটি প্রতিবন্ধকতা রয়েছে: যে সাদা প্যাশনগুলি কালো প্যাঁচাগুলি থেকে পৃথক করে সেই অবস্থানটি বাড়তে পারে না। সুতরাং বৈধ কনফিগারেশনের সংখ্যাটি সমান বা বৃহত্তর পজিশনের জন্য পূর্বের ত্রিভুজের বৈধ কনফিগারেশনের যোগফল হিসাবে গণনা করা হয়।

বেসিক ডিপি পদক্ষেপটি তখন খুব সহজ। একটি তির্যক প্রতিটি মান পূর্ববর্তী ত্রিভুজ থেকে মানগুলির যোগফল। কেবলমাত্র কিছুটা বেদনাদায়ক অংশ সূচকগুলি এবং লুপ রেঞ্জগুলি সঠিকভাবে গণনা করছে। যেহেতু আমরা তির্যকগুলিতে কাজ করছি, গণনার প্রথমার্ধের সময় দৈর্ঘ্য বৃদ্ধি পায় এবং দ্বিতীয়ার্ধের জন্য হ্রাস পায় যা লুপের গণনাটিকে আরও জটিল করে তোলে। বোর্ডের সীমানায় মানগুলির জন্য কিছু বিবেচনা আছে, যেহেতু তির্যক থেকে তির্যক পদক্ষেপের সময় তাদের একদিকে কেবল তির্যক প্রতিবেশী থাকে।

ব্যবহৃত মেমরির পরিমাণ হ'ল হে (এন ^ 3)। আমি রাষ্ট্রীয় তথ্য এবং তার মধ্যে পিং পংয়ের দুটি অনুলিপি রাখি। আমি বিশ্বাস করি রাষ্ট্রীয় তথ্যগুলির একক উদাহরণ দিয়ে পরিচালনা করা সম্ভব হবে। তবে আপনাকে খুব সতর্কতা অবলম্বন করতে হবে যে পুরানো মানগুলি সম্পূর্ণরূপে গ্রাস হওয়ার আগে কোনও মান আপডেট না হয়। এছাড়াও, আমি যে সমান্তরাল প্রক্রিয়াকরণটি প্রবর্তন করেছি তাতে এটি ভাল কাজ করবে না।

রানটাইম জটিলতা হ'ল ... বহুপদী। অ্যালগরিদমে 4 টি নেস্টেড লুপ রয়েছে, সুতরাং প্রথম দর্শনে এটি O (n ^ 4) এর মতো দেখাবে। তবে আপনার অবশ্যই এই আকারগুলিতে বিগিন্টস প্রয়োজন এবং সংখ্যাগুলি তারা আরও বড় আকারে আরও দীর্ঘায়িত হয়। ফলাফলের অঙ্কগুলির সংখ্যা আনুমানিক আনুপাতিকভাবে n এর সাথে বেড়েছে বলে মনে হচ্ছে যা পুরো জিনিসটিকে ও (এন ^ 5) করে তুলবে। অন্যদিকে, আমি কিছু কার্যকারিতা উন্নতি পেয়েছি, যা সমস্ত লুপের সম্পূর্ণ পরিসীমাটি অতিক্রম করে।

সুতরাং এটি এখনও মোটামুটি ব্যয়বহুল অ্যালগরিদম হলেও, এটি সমাধানগুলি গণনা করে এমন অ্যালগরিদমগুলির থেকে অনেক বেশি দূরে পেয়ে যায়, যা সমস্ত ক্ষতিকারক।

বাস্তবায়নের বিষয়ে কয়েকটি নোট:

  • যদিও কালো স্কোয়ারগুলিতে 2 * n ^ 2 টি কালো প্যাঁস থাকতে পারে, আমি কেবল কনফিগারেশন নম্বরগুলি n ^ 2 কালো প্যাঁক পর্যন্ত গণনা করি। যেহেতু কালো এবং সাদা প্যাঁকের মধ্যে একটি প্রতিসাম্য রয়েছে, তাই কে এবং 2 * n ^ 2-k এর কনফিগারেশন গণনা একই।
  • একই ধরণের প্রতিসাম্যের উপর ভিত্তি করে কালো স্কোয়ারগুলিতে কনফিগারেশন গণনা থেকে সমাধানের সংখ্যাটি শেষে গণনা করা হয়। সমাধানের মোট সংখ্যা (যার প্রতিটি রঙের 2 * n ^ 2 পাউন্ড হওয়া দরকার) হ'ল ব্ল্যাক পাউন্ডের জন্য এক রঙের স্কোয়ারের কনফিগারেশনের সংখ্যা 2 * n ^ 2-k ব্ল্যাক পাউন্ডার জন্য কনফিগারেশনের সংখ্যা দ্বারা গুণিত হয় স্কোয়ারের অন্যান্য রঙে, সমস্ত কে-এর উপরে যোগফল।
  • তির্যক অবস্থান এবং প্যাঁচের গণনা অনুসারে কেবল কনফিগারেশন গণনাগুলি সঞ্চয় করার পাশাপাশি আমি প্যাঙ্ক গণনাগুলির পরিসীমাও সঞ্চয় করি যা প্রতি পজিশনে বৈধ কনফিগারেশন রয়েছে। এটি যথেষ্ট পরিমাণে অভ্যন্তরীণ লুপের পরিসীমা কেটে ফেলতে দেয়। এটি ছাড়া আমি দেখতে পেলাম যে প্রচুর শূন্য যুক্ত করা হচ্ছে। আমি এ থেকে খুব যথেষ্ট পারফরম্যান্সের উন্নতি পেয়েছি।
  • অ্যালগরিদমটি বেশ ভালভাবে সমান্তরাল করে, বিশেষত বড় আকারের। ত্রিভুজগুলি ক্রমানুসারে প্রক্রিয়াগুলি সম্পন্ন করতে হবে, তাই প্রতিটি তীরের শেষে একটি বাধা রয়েছে। কিন্তু তির্যকের মধ্যে অবস্থানগুলি সমান্তরালভাবে প্রক্রিয়া করা যায়।
  • প্রোফাইলিং দেখায় যে বাধা স্পষ্টভাবে বিগিন্ট মানগুলি যুক্ত করার ক্ষেত্রে। আমি কোডের কিছু ভিন্নতা নিয়ে ঘুরেছি, তবে এটি খুব বেশি অনুকূলিত হয়নি। আমার সন্দেহ হয় যে ক্যারি সহ -৪-বিট সংযোজনগুলি ব্যবহার করতে ইনলাইন সমাবেশ থেকে উল্লেখযোগ্য উন্নতি হতে পারে।

প্রধান অ্যালগরিদম কোড। 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;
}

এটির জন্য একটি বিগিন্ট শ্রেণিও প্রয়োজন যা আমি এই উদ্দেশ্যে লিখেছিলাম। মনে রাখবেন এটি কোনও সাধারণ উদ্দেশ্যে বিগিন্ট শ্রেণি নয়। এই নির্দিষ্ট অ্যালগরিদম দ্বারা ব্যবহৃত অপারেশনগুলিকে সমর্থন করার জন্য এটি যথেষ্ট পরিমাণে রয়েছে:

#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

উপচ্ছায়া

এখানে একটি প্রাথমিক পোস্ট যা ফ্রেমওয়ার্ক সেট আপ করে। আমি মনে করি পদ্ধতিটি তুলনামূলকভাবে ভাল তবে বাস্তবায়ন এখনই ধরণের স্তন্যপায়ী। আমার সম্ভবত করা গণনার সংখ্যা হ্রাস করার চেষ্টা করা দরকার এবং এর পরিবর্তে আরও ধ্রুবকগুলি পাস করা উচিত।

কৌশল

মূলত, প্রতিটি সাদা প্যাঁচা অবশ্যই অন্যান্য সাদা পদ্মাগুলিতে আক্রমণ করবে। সুতরাং আমি একটি সাদা প্যাড রাখার মাধ্যমে শুরু করি, এটি আক্রমণ করে এমন প্রতিটি স্থানে प्याদা স্থাপন করে এবং সমস্ত জায়গাগুলিতে একটি সাদা পদ্মাগুলি যেতে বাধ্যতামূলকভাবে বোর্ডে পূরণ করি। আমি ইতিমধ্যে অনেক বেশি সাদা প্যাভ যুক্ত করেছি তবে আমি থামি। যদি এর শেষে, আমার কাছে ঠিক 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 সমাধানগুলি গণনা করে এমন পদ্ধতির কোনও সুযোগ নেই। যদি কোনও সন্দেহ থাকে তবে ফেয়ারসামের অ্যালগোরিদম দ্বারা উত্পাদিত নিখুঁত সংখ্যা তার প্রমাণ। কিছু ধরণের গতিশীল প্রোগ্রামিং অ্যালগরিদম যা তাদের গণনা ছাড়াই সমাধানের সংখ্যা গণনা করে এখানে যাওয়ার উপায়।
রেটো কোরাডি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.