2010-04-20 18 views
10

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

तब मैं समस्या को कैसे हल करूं? सभी संभावित पथों की जांच करके बलपूर्वक बल? मैं यह कैसे करना शुरू कर सकता हूं?

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

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

+1

चक्रीय ग्राफ पर सबसे लंबा रास्ता अनंत लंबाई का होगा, है ना? आप बस गोल और गोल और गोल और दौर जा रहे हैं ... – qrdl

+0

भले ही मैं देखे गए नोड्स को चिह्नित करता हूं, इसलिए मैं उनसे फिर से नहीं जाता? ऐसा कुछ है जो मैं अभी भी समझ नहीं पा रहा हूं क्यों। मेरे दिमाग में, यह डिज्कास्ट्रा एल्गोरिदम की तरह होना चाहिए, केवल "रिवर्स"। नीचे सुझाए गए की तरह, लेकिन मैं इसे काम करने में सक्षम नहीं हूं। एल्गोरिदम खत्म होता है, लेकिन परिणाम सही नहीं लगते हैं। –

उत्तर

8

समाधान बल को बल देना है। आप इसे गति देने के लिए कुछ अनुकूलन कर सकते हैं, कुछ छोटे हैं, कुछ बहुत जटिल हैं। मुझे संदेह है कि आप इसे डेस्कटॉप कंप्यूटर पर 18 000 नोड्स के लिए पर्याप्त तेज़ी से काम करने के लिए प्राप्त कर सकते हैं, और यहां तक ​​कि यदि आप मुझे नहीं जानते कि कैसे। यहां बताया गया है कि ब्रूटफोर्स कैसे काम करता है।

नोट: डिजस्ट्रा और अन्य सबसे कम पथ एल्गोरिदम इस समस्या के लिए काम नहीं करेंगे यदि आप एक सटीक उत्तर में रूचि रखते हैं। 1 - 2 (4), 1 - 3 (100), 2 - 3 (5), 3 - 5 (200), 3 - 4 (7), 4 - 5 (1000)

Let the root be 1. We call getLongestPath(1, 0); 
2 is marked as visited and getLongestPath(2, 4); is called 
D[2] = 0 < currSum = 4 so D[2] = 4. 
3 is marked as visited and getLongestPath(3, 4 + 5); is called 
D[3] = 0 < currSum = 9 so D[3] = 9. 
4 is marked as visited and getLongestPath(4, 9 + 7); is called 
D[4] = 0 < currSum = 16 so D[4] = 16. 
5 is marked as visited and getLongestPath(5, 16 + 1000); is called 
D[5] = 0 < currSum = 1016 so D[5] = 1016. 
getLongestPath(3, 1016 + 200); is called, but node 3 is marked as visited, so nothing happens. 
Node 5 has no more child nodes, so the function marks 5 as not visited and backtracks to 4. The backtracking will happen until node 1 is hit, which will end up setting D[3] = 100 and updating more nodes. 

यहाँ यह iteratively यह कैसी दिखाई देगी (परीक्षण नहीं है, बस एक मूल विचार):

Start at a root node *root* 
Let D[i] = longest path from node *root* to node i. D[*root*] = 0, and the others are also 0. 

void getLongestPath(node, currSum) 
{ 
    if node is visited 
     return; 
    mark node as visited; 

    if D[node] < currSum 
     D[node] = currSum; 

    for each child i of node do 
     getLongestPath(i, currSum + EdgeWeight(i, node)); 

    mark node as not visited; 
} 

के इस ग्राफ पर हाथ से चलाते हैं

Let st be a stack, the rest remains unchanged; 
void getLongestPath(root) 
{ 
    st.push(pair(root, 0)); 

    while st is not empty 
    { 
     topStack = st.top(); 
     if topStack.node is visited 
      goto end; 
     mark topStack.node as visited; 

     if D[topStack.node] < topStack.sum 
      D[topStack.node = topStack.sum; 

     if topStack.node has a remaining child (*) 
      st.push(pair(nextchild of topStack.node, topStack.sum + edge cost of topStack.node - nextchild)) 

     end: 
     mark topStack.node as not visited 
     st.pop(); 
    } 
} 

(*) - यह एक समस्या है - आपको प्रत्येक नोड के लिए अगले बच्चे को पॉइंटर रखना होगा, क्योंकि यह थोड़ी देर के लूप के विभिन्न पुनरावृत्तियों के बीच बदल सकता है और यहां तक ​​कि खुद को रीसेट कर सकता है (जब आप पॉप करते हैं तो सूचक खुद को रीसेट करता है ई topStack.node ढेर से नोड, इसलिए इसे रीसेट करना सुनिश्चित करें)। लिंक किए गए सूचियों पर इसे लागू करना सबसे आसान है, हालांकि आपको int[] सूचियों या vector<int> सूचियों का उपयोग करना चाहिए, ताकि पॉइंटर्स को स्टोर करने में सक्षम हो और यादृच्छिक पहुंच हो, क्योंकि आपको इसकी आवश्यकता होगी। आप उदाहरण के लिए next[i] = next child of node i in its adjacency list रख सकते हैं और तदनुसार अपडेट कर सकते हैं। आपके पास कुछ किनारे के मामले हो सकते हैं और उन्हें end: स्थितियों की आवश्यकता हो सकती है: एक सामान्य और एक ऐसा होता है जब आप पहले से देखे गए नोड पर जाते हैं, तो किस स्थिति में पॉइंटर्स को रीसेट करने की आवश्यकता नहीं होती है। इससे बचने के लिए स्टैक पर कुछ धक्का देने का फैसला करने से पहले शायद विज़िट की गई स्थिति को स्थानांतरित करें।

देखें मैंने क्यों कहा कि आपको परेशान नहीं होना चाहिए? :)

+0

मैं इस पर टिप्पणी नहीं कर सकता क्योंकि मुझे छोड़ना है, मैं अभी यह देखने के लिए आया हूं कि कोई जवाब है या नहीं। हालांकि, क्या इसे बिना किसी आसान तरीके से रिकर्सन किया जा सकता है या सिर्फ चीजों को जटिल करता है? जब मैं कक्षाओं से वापस आऊंगा तो मैं कुछ घंटों में अधिक समय के साथ आपकी पोस्ट की जांच करूंगा। –

+0

रिकर्सन का मतलब है कि एक अंतर्निहित स्टैक स्मृति में बनाए रखा जाता है, जहां प्रत्येक फ़ंक्शन कॉल के लिए फ़ंक्शन तर्क और स्थानीय चर जैसे चीजें धक्का दी जाती हैं।आप स्वयं को ढेर कर सकते हैं और इस प्रकार रिकर्सन से बच सकते हैं, हालांकि मुझे लगता है कि यह केवल चीजों को जटिल करता है। रिकर्सन यहां बाधा नहीं है। आपको इसके बजाय मानवीय अनुकूलन पर ध्यान देना चाहिए (उदाहरण के लिए, मुझे लगता है कि यदि आप 'डी [नोड]> = currSum' वापस लौट सकते हैं)। यह यात्रा विक्रेता की समस्या के समान है, इसलिए आप इसे Google पर देखना चाहते हैं और देख सकते हैं कि दूसरों के साथ क्या आया है। – IVlad

+0

इसके अलावा, एक अनुमानित एल्गोरिदम का उपयोग करने पर विचार करें। क्या आपको सबसे अच्छा संभव उत्तर भी वापस करना होगा, या कुछ भी करीब पर्याप्त है? लालची सन्निकटन एल्गोरिदम और आनुवंशिक एल्गोरिदम में देखने पर विचार करें। आनुवांशिक एल्गोरिदम आपको सबसे अच्छा समाधान भी प्राप्त कर सकते हैं यदि आप उन्हें काफी देर तक चलने देते हैं। – IVlad

संबंधित मुद्दे