इसके क्रमों द्वारा एक क्रम जानें


18

परिचय

मान लीजिए कि आप और आपका दोस्त एक गेम खेल रहे हैं। आपका मित्र nबिट्स के कुछ विशेष अनुक्रम के बारे में सोचता है , और आपका कार्य उन्हें प्रश्न पूछकर अनुक्रम को कम करना है। हालाँकि, आपके द्वारा पूछे जाने वाले एकमात्र प्रकार के प्रश्न "आपके अनुक्रम की सबसे लंबी सामान्य अनुवर्तीता कितनी लंबी है और S", Sबिट्स का कोई अनुक्रम कहाँ है। आपको जितने कम प्रश्नों की आवश्यकता होगी, उतना ही बेहतर होगा।

काम

आपका कार्य एक प्रोग्राम या फ़ंक्शन लिखना है जो इनपुट को एक सकारात्मक पूर्णांक n, और Rलंबाई के एक द्विआधारी अनुक्रम के रूप में लेता है n। अनुक्रम पूर्णांक, एक स्ट्रिंग, या अपनी पसंद के कुछ अन्य उचित प्रकार का एक सरणी हो सकता है। आपका कार्यक्रम अनुक्रम का उत्पादन करेगा R

आपके कार्यक्रम को सीधे अनुक्रम तक पहुंचने की अनुमति नहीं हैRकेवल बात यह है कि यह करने के लिए करने की अनुमति दी है Rफ़ंक्शन का इनपुट के रूप में यह दे रहा है len_lcsएक और बाइनरी अनुक्रम के साथ S। समारोह len_lcs(R, S)की सबसे लंबी आम subsequence की लंबाई देता है Rऔर S। इसका अर्थ है बिट्स का सबसे लंबा क्रम जो दोनों ( Rऔर जरूरी नहीं कि सन्निहित) के रूप में होता है Slen_lcsजिनके इनपुट अलग-अलग लंबाई के हो सकते हैं। कार्यक्रम को इस फ़ंक्शन को Rकुछ समय पर और अन्य अनुक्रमों पर कॉल करना चाहिए , और फिर Rउस जानकारी के आधार पर अनुक्रम का पुनर्निर्माण करना चाहिए ।

उदाहरण

इनपुट पर विचार करें n = 4और R = "1010"। सबसे पहले, हम मूल्यांकन कर सकते हैं len_lcs(R, "110"), जो देता है 3, क्योंकि "110"सबसे लंबे समय तक सामान्य है "1010"और "110"। तब हम जानते हैं कि किसी स्थिति में एक बिट डालने 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, और फिर flipping एक a-biased सिक्का nबार। आप इन अनुक्रमों पर कॉलlen_lcs की औसत संख्या है , कम स्कोर बेहतर है। आपके सबमिशन में कॉल की संख्या दर्ज होनी चाहिए। कोई समय सीमा नहीं है, सिवाय इसके कि आपको अपना कार्यक्रम फ़ाइल पर भेजने से पहले चलाना चाहिए।

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

यह कोड गोल्फ नहीं है, इसलिए आपको पठनीय कोड लिखने के लिए प्रोत्साहित किया जाता है। रोसेटा कोड में सबसे लंबे समय तक सामान्य पृष्ठ पर एक पृष्ठ है ; आप len_lcsअपनी पसंद की भाषा में लागू करने के लिए इसका उपयोग कर सकते हैं ।


शांत विचार! क्या इसका कोई अनुप्रयोग है?
दोष

@flawr मैं किसी भी प्रत्यक्ष अनुप्रयोगों के बारे में नहीं जानता। विचार क्वेरी जटिलता सिद्धांत , कंप्यूटर विज्ञान के एक उपक्षेत्र से आया है , और जिसमें अनुप्रयोगों का भार है।
जरगब 21:16

मुझे लगता है कि फिर से उसी चुनौती को प्राप्त करना बहुत अच्छा होगा लेकिन आप lcsइसके बजाय कहां पहुंच सकते हैं len_lcs
दोष

@flawr lcs(R, "01"*2*n)रिटर्न के बाद से बहुत दिलचस्प नहीं होगा R। ;) लेकिन वह काम कर सकता है अगर कॉलिंग 1 के बजाय lcs(R, S)स्कोर बढ़ाएगी len(S), या ऐसा ही कुछ ...
ज़र्गब

1
मुझे अन्य उत्तर = S
त्रुटी

जवाबों:


10

जावा, 99.04 98.46 97.66 LCS () कॉल

यह काम किस प्रकार करता है

एक्साप्ले: हमारी लाइन जिसे फिर से बनाना है 00101। पहले हम पता लगाते हैं कि कितने शून्य हैं (केवल मूल स्ट्रिंग के साथ गणना = कंप्यूटिंग एलएसी की तुलना करके) कितने शून्य हैं 00000। फिर हम प्रत्येक स्थिति से गुजरते हैं, 01और फ्लिप करते हैं और जांचते हैं कि क्या हमारे पास अब सामान्य प्रतिस्थापन है। यदि हाँ, तो स्वीकार करें और अगली स्थिति पर जाएं, यदि नहीं, तो वर्तमान को 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जांच की आवश्यकता है । (अंतिम अंकों के होने पर एक को बदलें 1)

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

EDIT2: मैंने अभी देखा कि आप अंतिम विचार से ऊपर विचार कर सकते 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 की तुलना में अधिक 1s हैं जो आप 1 पदों के बजाय 0 पदों पर शिकार करने के लिए स्विच करते हैं। आप ऐसा कई बार भी कर सकते हैं।
हिस्टोक्रैट

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