এর অনুচ্ছেদগুলি অনুসারে একটি ক্রম জানুন


18

ভূমিকা

মনে করুন আপনি এবং আপনার বন্ধু একটি খেলা খেলছেন। আপনার বন্ধু nবিটের কিছু নির্দিষ্ট ক্রম সম্পর্কে ভাবেন এবং আপনার কাজটি তাদের প্রশ্ন জিজ্ঞাসা করে ক্রমটি হ্রাস করা। তবে, আপনাকে কেবলমাত্র এক ধরণের প্রশ্ন জিজ্ঞাসা করার অনুমতি দেওয়া হ'ল "আপনার সিকোয়েন্সের দীর্ঘতম সাধারণ অনুচ্ছেদটি কত দীর্ঘ এবং S", যেখানে Sবিটের কোনও অনুক্রম রয়েছে। আপনার যত কম প্রশ্ন দরকার, তত ভাল।

কাজটি

আপনার কাজ হ'ল একটি প্রোগ্রাম বা ফাংশন লিখুন যা ইনপুট হিসাবে ধনাত্মক পূর্ণসংখ্যার nএবং Rদৈর্ঘ্যের একটি বাইনারি ক্রম নেয় n। ক্রমটি পূর্ণসংখ্যার অ্যারে, স্ট্রিং বা আপনার পছন্দ মতো কিছু যুক্তিসঙ্গত ধরণের হতে পারে। আপনার প্রোগ্রাম ক্রম আউটপুট হবে R

তোমার প্রোগ্রাম হয় না ক্রম অ্যাক্সেসের অনুমতি Rসরাসরি। শুধুমাত্র জিনিস এটি করতে অনুমোদিত Rফাংশনে ইনপুট যেমন দিতে হয় len_lcsঅন্য বাইনারি ক্রম সহ S। ফাংশন len_lcs(R, S)দীর্ঘতম সাধারণ subsequence দৈর্ঘ্য ফেরৎ Rএবং S। এর অর্থ বিটের দীর্ঘতম ক্রম যা উভয় Rএবং এর মধ্যে একটি (অগত্যা সংগত নয়) উপসংশ হিসাবে ঘটে S। যার ইনপুটগুলি len_lcsবিভিন্ন দৈর্ঘ্যের হতে পারে। প্রোগ্রামটি এই ফাংশনটি Rএবং অন্যান্য সিকোয়েন্সগুলি কয়েকবার কল করে এবং তারপরে Rসেই তথ্যের উপর ভিত্তি করে ক্রমটি পুনর্গঠন করে ।

উদাহরণ

ইনপুট n = 4এবং বিবেচনা করুন R = "1010"। প্রথমত, আমরা মূল্যায়ন পারে len_lcs(R, "110"), যা দেয় 3, যেহেতু "110"দীর্ঘতম সাধারণ subsequence হয় "1010"এবং "110"। তারপরে আমরা জানি যে কিছু অবস্থানে একটি বিট byোকানো দ্বারা Rপ্রাপ্ত করা হয়েছে "110"। এর পরে, আমরা চেষ্টা করতে পারি len_lcs(R, "0110"), যেটি 3সবচেয়ে দীর্ঘকালীন সাধারণ অনুচ্ছেদগুলি যেহেতু ফিরে আসে "110"এবং "010"তাই "0110"সঠিক নয়। তারপরে আমরা চেষ্টা করি len_lcs(R, "1010"), যা ফিরে আসে 4। এখন আমরা এটি জানি R == "1010", সুতরাং আমরা সেই অনুক্রমটিকে সঠিক আউটপুট হিসাবে ফিরিয়ে দিতে পারি। এটিতে 3 টি কল প্রয়োজন len_lcs

বিধি এবং স্কোরিং

ইন এই সংগ্রহস্থলের , আপনি নামক একটি ফাইল পাবেন subsequence_data.txt75 এবং 124. মধ্যে লেন্থ 100 র্যান্ডম বাইনারি সিকোয়েন্স তারা 0 এবং 1 এর মধ্যে তিনটি র্যান্ডম ভাসে গ্রহণ হিসেবে তাদের গড় গ্রহণ করে উত্পন্ন হয় ধারণকারী a, এবং তারপর আলোকসম্পাতের একটি a-biased মুদ্রা nবার। আপনি এই স্কোরগুলিতে কল করার গড় সংখ্যাlen_lcs হ'ল কম স্কোর আরও ভাল। আপনার জমা দেওয়ার ক্ষেত্রে কলগুলির সংখ্যা রেকর্ড করা উচিত। কোনও সময়সীমা নেই, কেবলমাত্র আপনার প্রোগ্রামটি জমা দেওয়ার আগে ফাইলটিতে চালানো উচিত।

আপনার জমাটি সংজ্ঞাবহ হতে হবে। PRNGs অনুমোদিত, কিন্তু তাদের অবশ্যই আজকের তারিখটি 200116(বা নিকটতম সমতুল্য) এলোমেলো বীজ হিসাবে ব্যবহার করতে হবে। এই নির্দিষ্ট পরীক্ষার ক্ষেত্রে আপনার জমাটি অপ্টিমাইজ করার অনুমতি নেই। যদি সন্দেহ হয় যে এটি ঘটছে তবে আমি একটি নতুন ব্যাচ তৈরি করব।

এটি কোড গল্ফ নয়, তাই আপনাকে পঠনযোগ্য কোড লেখার জন্য উত্সাহ দেওয়া হচ্ছে। রোজটা কোডের দীর্ঘতম সাধারণ অনুচ্ছেদে একটি পৃষ্ঠা রয়েছে ; আপনি len_lcsএটি আপনার পছন্দসই ভাষায় প্রয়োগ করতে পারেন ।


দুর্দান্ত ধারণা! এটির কি কোনও অ্যাপ্লিকেশন রয়েছে?
flawr

@ ফ্লোয়ার আমি কোনও সরাসরি অ্যাপ্লিকেশন সম্পর্কে জানি না। ধারণাটি জটিলতার তত্ত্ব , কম্পিউটার বিজ্ঞানের একটি সাবফিল্ড, এবং এতে প্রচুর অ্যাপ্লিকেশন রয়েছে from
Zgarb

আমি আবার একই চ্যালেঞ্জ পেলে দুর্দান্ত হবে তবে আপনি যেখানে এর lcsপরিবর্তে অ্যাক্সেস করতে পারেন তা মনে হয় len_lcs
flawr

@ ফ্লোয়ার lcs(R, "01"*2*n)রিটার্নের পর থেকে এটি খুব আকর্ষণীয় হবে না R। ;) তবে এটি কাজ করতে পারে যদি কল করা 1 এর পরিবর্তে lcs(R, S)স্কোর len(S)বা আরও কিছু বাড়িয়ে দেয় ...
জাগারব

1
আমি অন্যান্য উত্তরগুলি দেখতে চাই = এস
ফ্লোয়ার

উত্তর:


10

জাভা, 99.04 98.46 97.66 এলসিএস () কল

কিভাবে এটা কাজ করে

পদক্ষেপ: আমাদের লাইনটি পুনর্গঠন করা হয় 00101। প্রথমে কেবলমাত্র একটি জিরো স্ট্রিং দিয়ে তুলনা করে (এখানে মূল স্ট্রিংয়ের সাথে = কম্পিউটিং এলসিএস তুলনা করে) কত জিরো রয়েছে তা খুঁজে বের করি 00000। তারপর আমরা প্রতিটি পদের মধ্য দিয়ে যেতে, টুসকি 0একটি থেকে 1এবং চেক যদি আমরা এখন একটি লম্বা সাধারণ সাবস্ট্রিং আছে। যদি হ্যাঁ, গ্রহণ করুন এবং পরবর্তী অবস্থানে যান, যদি না হয় তবে বর্তমানটিকে 1একটি তে ফ্লিপ করুন 0এবং পরবর্তী অবস্থানে যান:

For our example of "00101" we get following steps:
input  lcs  prev.'best'
00000  3    0           //number of zeros
̲10000  3    3           //reject
0̲1000  3    3           //reject
00̲100  4    3           //accept
001̲10  4    4           //reject
0010̲1  5    4           //accept

নিখুঁতকরণ

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

একটি প্রদত্ত অঙ্কের রেখার জন্য, এই অ্যালগরিদমের জন্য ঠিক #ofDigitsUntilTheLastOccurenceOf1 + 1চেক দরকার che (শেষ সংখ্যাটি যদি একটি হয় তবে বিয়োগ করুন 1))

সম্পাদনা: একটি ছোট অপ্টিমাইজেশন: আমরা যদি মাত্র ২ য় শেষ সংখ্যাটি পরীক্ষা করেছিলাম এবং এখনও আমাদের একটি সন্নিবেশ করা প্রয়োজন 1, আমরা নিশ্চিতভাবে জানি যে এটি অবশ্যই খুব শেষ অবস্থানে থাকতে হবে, এবং সংশ্লিষ্ট চেকটি বাদ দিতে পারে।

সম্পাদনা 2: আমি কেবল লক্ষ্য করেছি আপনি শেষের উপরের ধারণাটি প্রয়োগ করতে পারেন k

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

রানটাইম

উপরের সীমাটি O(#NumberOfBits)

সম্পূর্ণ কোড

এখানে সম্পূর্ণ কোড:

package jcodegolf;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

// http://codegolf.stackexchange.com/questions/69799/know-a-sequence-by-its-subsequences

public class SequenceReconstructor { 
    public static int counter = 0;
    public static int lcs(String a, String b) { //stolen from http://rosettacode.org/wiki/Longest_common_subsequence#Java
        int[][] lengths = new int[a.length()+1][b.length()+1];

        // row 0 and column 0 are initialized to 0 already

        for (int i = 0; i < a.length(); i++)
            for (int j = 0; j < b.length(); j++)
                if (a.charAt(i) == b.charAt(j))
                    lengths[i+1][j+1] = lengths[i][j] + 1;
                else
                    lengths[i+1][j+1] =
                        Math.max(lengths[i+1][j], lengths[i][j+1]);

        // read the substring out from the matrix
        StringBuffer sb = new StringBuffer();
        for (int x = a.length(), y = b.length();
             x != 0 && y != 0; ) {
            if (lengths[x][y] == lengths[x-1][y])
                x--;
            else if (lengths[x][y] == lengths[x][y-1])
                y--;
            else {
                assert a.charAt(x-1) == b.charAt(y-1);
                sb.append(a.charAt(x-1));
                x--;
                y--;
            }
        }

        counter ++;
        return sb.reverse().toString().length();
    }


    public static String reconstruct(String secretLine, int lineLength){
        int current_lcs = 0; 
        int previous_lcs = 0;
        char [] myGuess = new char[lineLength];
        for (int k=0; k<lineLength; k++){
            myGuess[k] = '0';
        }

        //find the number of zeros:
        int numberOfZeros = lcs(secretLine, String.valueOf(myGuess));
        current_lcs = numberOfZeros;
        previous_lcs = numberOfZeros;

        if(current_lcs == lineLength){ //were done
            return String.valueOf(myGuess);
        }


        int numberOfOnes = lineLength - numberOfZeros;
        //try to greedily insert ones at the positions where they maximize the common substring length
        int onesCounter = 0;
        for(int n=0; n < lineLength && onesCounter < numberOfOnes; n++){

            myGuess[n] = '1';
            current_lcs = lcs(secretLine, String.valueOf(myGuess));

            if(current_lcs > previous_lcs){ //accept

                previous_lcs = current_lcs;
                onesCounter ++;

            } else { // do not accept
                myGuess[n]='0';     
            }

            if(n == lineLength-(numberOfOnes-onesCounter)-1 && onesCounter < numberOfOnes){ //lets test if we have as many locations left as we have ones to insert
                                                                // then we know that the rest are ones
                for(int k=n+1;k<lineLength;k++){
                    myGuess[k] = '1';
                }
                break;
            }

        }

        return String.valueOf(myGuess);
    }

    public static void main(String[] args) {
        try {

            //read the file
            BufferedReader br;

            br = new BufferedReader(new FileReader("PATH/TO/YOUR/FILE/LOCATION/subsequence_data.txt"));

            String line;

            //iterate over each line
            while ( (line = br.readLine()) != null){

                String r = reconstruct(line, line.length());
                System.out.println(line);     //print original line
                System.out.println(r);        //print current line
                System.out.println(counter/100.0);  //print current number of calls
                if (! line.equals(r)){
                    System.out.println("SOMETHING WENT HORRIBLY WRONG!!!");
                    System.exit(1);
                }

            }


        } catch(Exception e){
            e.printStackTrace();;
        }

    }

}

1
যেহেতু আপনি যখন 1 টি পেছনে পিছনে কম কল পেয়েছেন, মনে হয় আপনি গড়ের চেয়ে আরও ভাল করতে পারতেন, প্রথম অনুমানের পরে যদি আপনি 1s এর চেয়ে 0 পজিশনের পরিবর্তে 0 টি পজিশন অনুসন্ধানের পরিবর্তে 1s এর চেয়ে 0 0 এর বেশি হন। এমনকি আপনি একাধিক বার করতে পারেন।
হিস্টোক্র্যাট

1
@ ইতিহাসবিদ আমার মনে হয় তিনি একবারে শেষটি ব্যবহার করলে তিনি ইতিমধ্যে থেমে যাচ্ছেন 1, যা কেবলমাত্র শূন্যের বাকী থাকার সমতুল্য।
মার্টিন এন্ডার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.