केवल एक ट्रावेल के साथ एक अप्रत्यक्ष पेड़ में सबसे लंबा रास्ता


44

दो गहराई-पहली खोजों का उपयोग करते हुए अप्रत्यक्ष पेड़ों में सबसे लंबा रास्ता खोजने के लिए यह मानक एल्गोरिथ्म है:

  • DFS को एक यादृच्छिक वर्टेक्स से प्रारंभ करें और उससे सबसे दूर का शीर्ष ज्ञात करें; यह ।vv
  • अब से शुरू करें ताकि उसमें से सबसे दूर का पता लगाया जा सके। यह रास्ता ग्राफ में सबसे लंबा रास्ता है।v

सवाल यह है कि क्या यह अधिक कुशलता से किया जा सकता है? क्या हम इसे एकल डीएफएस या बीएफएस के साथ कर सकते हैं?

(इसे एक अप्रत्यक्ष वृक्ष के व्यास की गणना की समस्या के रूप में वर्णित किया जा सकता है ।)


2
इसके बाद आप जो हैं उसे पेड़ का व्यास भी कहा जाता है । (पेड़ों पर, "सबसे लंबे समय तक कम से कम पथ" और "सबसे लंबे समय तक पथ" एक ही बात सिर्फ एक ही किसी भी दो नोड्स जोड़ने पथ है, क्योंकि कर रहे हैं।)
राफेल

जवाबों:


22

हम पोस्ट ऑर्डर में गहराई से पहली खोज करते हैं और रास्ते में परिणाम एकत्र करते हैं, यही समस्या है कि हम पुनरावर्ती रूप से हल करते हैं।

बच्चों के साथ प्रत्येक नोड के लिए (खोज ट्री में) दो मामले हैं:vu1,,uk

  • में सबसे लंबा रास्ता में से एक में निहित है ।TvTu1,,Tuk
  • में सबसे लंबे पथ में ।Tvv

दूसरे मामले में, हमें एक या दो सबसे लंबे रास्तों को से एक सबस्ट्रेसेस में संयोजित करना है ; ये निश्चित रूप से सबसे गहरी पत्तियों के हैं। पथ की लंबाई तब अगर , या यदि , सबट्री हाइट्स का बहु सेट।vH(k)+H(k1)+2k>1H(k)+1k=1H={h(Tui)i=1,,k}

छद्म कोड में, एल्गोरिथ्म इस तरह दिखता है:

procedure longestPathLength(T : Tree) = helper(T)[2]

/* Recursive helper function that returns (h,p)
 * where h is the height of T and p the length
 * of the longest path of T (its diameter) */
procedure helper(T : Tree) : (int, int) = {
  if ( T.children.isEmpty ) {
    return (0,0)
  }
  else {
    // Calculate heights and longest path lengths of children
    recursive = T.children.map { c => helper(c) }
    heights = recursive.map { p => p[1] }
    paths = recursive.map { p => p[2] }

    // Find the two largest subtree heights
    height1 = heights.max
    if (heights.length == 1) {
      height2 = -1
    } else {
      height2 = (heights.remove(height1)).max
    }

    // Determine length of longest path (see above)        
    longest = max(paths.max, height1 + height2 + 2)

    return (height1 + 1, longest)
  }
}

  1. A(k) है में -smallest मूल्य (क्रम आंकड़ा)।kA

@JeffE दूसरी टिप्पणी के बारे में: वास्तव में, और यह अंतिम पंक्ति में ध्यान रखा जाता है: height1 + height2इस पथ की लंबाई है। यदि यह वास्तव में सबसे लंबा रास्ता है, तो इसे चुना जाता है max। यह ऊपर के पाठ में भी समझाया गया है, इसलिए मुझे आपकी समस्या नहीं दिख रही है? निश्चित रूप से आपको यह पता लगाने के लिए पुनरावृत्ति करनी होगी कि क्या यह वास्तव में सबसे लंबा रास्ता है, और यहां तक ​​कि अगर यह (आरईटी शुद्धता) को पुनरावृत्ति करने के लिए चोट नहीं करता है।
राफेल

@ जेफ़े पहली टिप्पणी के बारे में, height2स्पष्ट रूप height1से विचार के लिए गणना को हटा देता है, इसलिए यह एक ही बच्चे को दो बार कैसे चुन सकता है? यह भी, परिचयात्मक पाठ में समझाया गया है।
राफेल

1
जाहिरा तौर पर, हम अलग-अलग स्यूडोकोड बोलियाँ बोलते हैं, क्योंकि मेरे पास आपको समझने में कठिन समय है। यह एक स्पष्ट अंग्रेजी घोषणा को जोड़ने में मदद करेगा जो longestPathHeight(T)एक जोड़ी लौटाता है (h,d), जहां hकी ऊंचाई है Tऔर dका व्यास है T। (दाएं?)
जेफ ईई

@ जेफ़े राइट; मैंने सोचा था कि कोड से स्पष्ट था, स्पष्टीकरण दिया गया था, लेकिन जाहिरा तौर पर अन्य छद्मकोड-प्रतिमानों के लिए "स्पष्ट" का मेरा अपवाद अपर्याप्त था (मेरा स्केलेस्क है, मुझे लगता है)। भ्रम के लिए क्षमा करें, मैं कोड स्पष्ट कर रहा हूं (उम्मीद है)।
राफेल

8

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

यहाँ एक सारांश है जो मैं अपने ब्लॉग पोस्ट में बताना चाहता हूँ :

पुनरावर्ती दृष्टिकोण - ट्री व्यास इस समस्या से संपर्क करने का एक और तरीका इस प्रकार है। जैसा कि हमने ऊपर बताया कि व्यास कर सकते हैं

  1. पूरी तरह से बाईं उप पेड़ या में झूठ बोलते हैं
  2. पूरी तरह से सही उप पेड़ या में झूठ बोलते हैं
  3. जड़ तक फैल सकता है

जिसका अर्थ है कि व्यास को आदर्श रूप से प्राप्त किया जा सकता है

  1. बाएं पेड़ का व्यास या
  2. सही पेड़ का व्यास या
  3. बाएं उप पेड़ की ऊंचाई + दाहिने उप पेड़ की ऊंचाई + (1 रूट नोड जोड़ने के लिए जब व्यास जड़ नोड भर में फैला है)

और हम जानते हैं कि व्यास सबसे लंबा रास्ता है, इसलिए हम अधिकतम 1 और 2 को लेते हैं यदि यह पक्ष में है या मूत 3 लेता है यदि यह जड़ से फैला है।

Iterative दृष्टिकोण - ट्री व्यास

हमारे पास एक पेड़ है, हमें प्रत्येक नोड के साथ एक मेटा जानकारी की आवश्यकता है ताकि प्रत्येक नोड निम्नलिखित को जान सके:

  1. इसके बाएं बच्चे की ऊंचाई,
  2. अपने सही बच्चे की ऊंचाई और
  3. इसकी पत्ती नोड्स के बीच सबसे दूर की दूरी।

एक बार जब प्रत्येक नोड को यह जानकारी होती है, तो हमें अधिकतम पथ का ट्रैक रखने के लिए एक अस्थायी चर की आवश्यकता होती है। जब तक एल्गोरिथ्म खत्म हो जाता है, तब तक हम अस्थायी चर में व्यास का मान रखते हैं।

अब, हमें इस समस्या को नीचे के दृष्टिकोण में हल करने की आवश्यकता है, क्योंकि हमें रूट के लिए तीन मूल्यों के बारे में कोई पता नहीं है। लेकिन हम पत्तियों के लिए इन मूल्यों को जानते हैं।

हल करने के लिए कदम

  1. 1 के रूप में छोड़ दिया और राइटहाइट के साथ सभी पत्तियों को प्रारंभ करें।
  2. मैक्सिडिस्टेंस के साथ सभी पत्तियों को 0 के रूप में आरम्भ करें, हम इसे एक बिंदु बनाते हैं कि यदि बाईं या दाईं ओर 1 है तो हम मैक्सडिस्टेंस = 0 बनाते हैं।
  3. एक समय में एक ऊपर की ओर बढ़ें और तत्काल माता-पिता के लिए मूल्यों की गणना करें। यह आसान होगा क्योंकि अब हम बच्चों के लिए इन मूल्यों को जानते हैं।
  4. दिए गए नोड पर,

    • (अपने बाएं बच्चे के बाएं या दाएं अधिकतम) के रूप में बाएं हाथ को असाइन करें।
    • राइटहाइट को अधिकतम (बाएं राइट या राइट बच्चे के राइटहाइट) के रूप में असाइन करें।
    • यदि इनमें से कोई भी मान (बाएं या दायां) 1 अधिकतम अधिकतम शून्य है।
    • यदि दोनों मान शून्य से अधिक हैं तो बायाँ भाग को बायाँ + दायाँ दाईं ओर बनायें - 1
  5. एक अस्थायी चर में maxDistance बनाए रखें और अगर चरण 4 में maxDistance चर के वर्तमान मूल्य से अधिक है, तो इसे नए maxDistance मान से बदलें।
  6. एल्गोरिथ्म के अंत में मैक्सडिस्टेंस में मान व्यास है।

1
यह मेरे पुराने उत्तर पर क्या करता है, इसके अलावा कम सामान्य (आप केवल बाइनरी पेड़ों से निपटते हैं)?
राफेल

9
यह जवाब मेरी राय में समझने के लिए अधिक पठनीय और आसान है (आपका छद्म कोड बहुत भ्रामक है)।
रेगैगिटेरिट

-3

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

 int getDiam(int root, vector<vector<int>>& adj_list, int& height, vector<int>& path, vector<int>& diam) {
    visited[root] = true;
    int m1 = -1;
    int m2 = -1;
    int max_diam = -1;
    vector<int> best1 = vector<int>();
    vector<int> best2 = vector<int>();
    vector<int> diam_path = vector<int>();
    for(auto n : adj_list[root]) {
        if(!visited[n]) {
            visited[n] = true;
            int _height = 0;
            vector<int> path1;
            vector<int> path2;
            int _diam = getDiam(n, adj_list, _height, path1, path2);
            if(_diam > max_diam) {
                max_diam = _diam;
                diam_path = path2;
            }
            if(_height > m1) {
                m2 = m1;
                m1 = _height;
                best2 = best1;
                best1 = path1;
            }
            else if(_height > m2) {
                m2 = _height;
                best2 = path1;
            }
        }
    }

    height = m1 + 1;

    path.insert( path.end(), best1.begin(), best1.end() );
    path.push_back(root);

    if(m1 + m2 + 2 > max_diam) {
        diam = path;
        std::reverse(best2.begin(), best2.end());
        diam.insert( diam.end(), best2.begin(), best2.end() );
    }
    else{
        diam = diam_path;
    }


    return max(m1 + m2 + 2, max_diam);
}

2
यह कोई कोडिंग साइट नहीं है। हम उन उत्तरों को हतोत्साहित करते हैं जिनमें मुख्य रूप से कोड का एक ब्लॉक होता है। इसके बजाय, हम ऐसे उत्तर चाहते हैं जो एल्गोरिथ्म के पीछे के विचारों को समझाते हैं, और संक्षिप्त छद्म कोड देते हैं (जिसे समझने के लिए किसी विशेष प्रोग्रामिंग भाषा के ज्ञान की आवश्यकता नहीं है)। आप पेड़ में एक विशेष नोड पर शुरू होने वाले सबसे लंबे पथ की गणना कैसे करते हैं? (विशेष रूप से के बाद से सबसे लंबे समय तक पथ "ऊपर" डीएफएस पेड़, यानी, जड़ की ओर वापस जा रहा द्वारा शुरू कर सकते हैं)
DW
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.