ग्राफ़ एल्गोरिथ्म दो महत्वाकांक्षी कार्यक्षेत्रों के बीच सभी कनेक्शन खोजने के लिए


117

मैं नीचे वर्णित कार्य को पूरा करने के लिए सबसे अच्छा समय कुशल एल्गोरिदम निर्धारित करने की कोशिश कर रहा हूं।

मेरे पास रिकॉर्ड का एक सेट है। इस रिकॉर्ड के सेट के लिए मेरे पास कनेक्शन डेटा है जो दर्शाता है कि इस सेट से रिकॉर्ड के जोड़े एक दूसरे से कैसे जुड़ते हैं। यह मूल रूप से एक अप्रत्यक्ष ग्राफ का प्रतिनिधित्व करता है, जिसमें अभिलेख कोने और कनेक्शन डेटा किनारों के साथ होता है।

सेट के सभी रिकॉर्ड में कनेक्शन की जानकारी होती है (अर्थात कोई भी अनाथ रिकॉर्ड मौजूद नहीं होता है; सेट में प्रत्येक रिकॉर्ड सेट में एक या अधिक रिकॉर्ड से जुड़ता है)।

मैं सेट से कोई भी दो रिकॉर्ड चुनना चाहता हूं और चुने हुए रिकॉर्ड के बीच सभी सरल पथ दिखाने में सक्षम हो सकता हूं। "सरल रास्तों" से मेरा तात्पर्य उन रास्तों से है जिनका पथ में दोहराव नहीं है (केवल परिमित पथ)।

नोट: दो चुने हुए रिकॉर्ड हमेशा अलग-अलग होंगे (यानी स्टार्ट एंड एंड वर्टेक्स कभी भी एक जैसा नहीं होगा; कोई साइकिल नहीं)।

उदाहरण के लिए:

    अगर मेरे पास निम्नलिखित रिकॉर्ड हैं:
        ए, बी, सी, डी, ई

    और निम्नलिखित कनेक्शन का प्रतिनिधित्व करता है: 
        (ए, बी), (ए, सी), (बी, ए), (बी, डी), (बी, ई), (बी, एफ), (सी, ए), (सी, ई),
        (सी, एफ), (डी, बी), (ई, सी), (ई, एफ), (एफ, बी), (एफ, सी), (एफ, ई)

        [जहां (ए, बी) का मतलब रिकॉर्ड ए रिकॉर्ड बी से जोड़ता है]

अगर मैंने अपने शुरुआती रिकॉर्ड के रूप में बी को चुना और ई को मेरे अंत रिकॉर्ड के रूप में चुना, तो मैं रिकॉर्ड कनेक्शन के माध्यम से सभी सरल पथ खोजना चाहूंगा जो रिकॉर्ड बी को रिकॉर्ड ई से जोड़ देगा।

   B से E को जोड़ने वाले सभी रास्ते:
      बी> ई
      बी> F-> ई
      बी> F-> सी> ई
      बी> A-> सी> ई
      बी> A-> सी> F-> ई

यह एक उदाहरण है, व्यवहार में मेरे पास सैकड़ों हजारों रिकॉर्ड्स हो सकते हैं।


कनेक्शन को चक्र कहा जाता है , और इस उत्तर में आपके लिए बहुत सारे सुझाव हैं।
इलाहोम

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

क्या कोई इसके लिए सहायता कर सकता है ??? stackoverflow.com/questions/32516706/…
tejas3006

जवाबों:


116

ऐसा प्रतीत होता है कि यह ग्राफ की गहराई-पहली खोज के साथ पूरा किया जा सकता है। गहराई-पहली खोज में दो नोड्स के बीच सभी गैर-चक्रीय रास्ते मिलेंगे। यह एल्गोरिथ्म बहुत तेज़ होना चाहिए और बड़े ग्राफ़ के पैमाने पर होना चाहिए (ग्राफ़ डेटा संरचना विरल है, इसलिए यह केवल उतनी ही मेमोरी का उपयोग करता है जितना इसे आवश्यक है)।

मैंने देखा कि आपके द्वारा निर्दिष्ट ग्राफ़ में केवल एक किनारे है जो दिशात्मक (बी, ई) है। क्या यह एक टाइपो था या यह वास्तव में एक निर्देशित ग्राफ है? यह समाधान परवाह किए बिना काम करता है। क्षमा करें, मैं इसे C में करने में असमर्थ था, मैं उस क्षेत्र में थोड़ा कमजोर हूं। मुझे उम्मीद है कि आप इस जावा कोड का अनुवाद बिना अधिक परेशानी के कर पाएंगे।

Graph.java:

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

public class Graph {
    private Map<String, LinkedHashSet<String>> map = new HashMap();

    public void addEdge(String node1, String node2) {
        LinkedHashSet<String> adjacent = map.get(node1);
        if(adjacent==null) {
            adjacent = new LinkedHashSet();
            map.put(node1, adjacent);
        }
        adjacent.add(node2);
    }

    public void addTwoWayVertex(String node1, String node2) {
        addEdge(node1, node2);
        addEdge(node2, node1);
    }

    public boolean isConnected(String node1, String node2) {
        Set adjacent = map.get(node1);
        if(adjacent==null) {
            return false;
        }
        return adjacent.contains(node2);
    }

    public LinkedList<String> adjacentNodes(String last) {
        LinkedHashSet<String> adjacent = map.get(last);
        if(adjacent==null) {
            return new LinkedList();
        }
        return new LinkedList<String>(adjacent);
    }
}

Search.java:

import java.util.LinkedList;

public class Search {

    private static final String START = "B";
    private static final String END = "E";

    public static void main(String[] args) {
        // this graph is directional
        Graph graph = new Graph();
        graph.addEdge("A", "B");
        graph.addEdge("A", "C");
        graph.addEdge("B", "A");
        graph.addEdge("B", "D");
        graph.addEdge("B", "E"); // this is the only one-way connection
        graph.addEdge("B", "F");
        graph.addEdge("C", "A");
        graph.addEdge("C", "E");
        graph.addEdge("C", "F");
        graph.addEdge("D", "B");
        graph.addEdge("E", "C");
        graph.addEdge("E", "F");
        graph.addEdge("F", "B");
        graph.addEdge("F", "C");
        graph.addEdge("F", "E");
        LinkedList<String> visited = new LinkedList();
        visited.add(START);
        new Search().depthFirst(graph, visited);
    }

    private void depthFirst(Graph graph, LinkedList<String> visited) {
        LinkedList<String> nodes = graph.adjacentNodes(visited.getLast());
        // examine adjacent nodes
        for (String node : nodes) {
            if (visited.contains(node)) {
                continue;
            }
            if (node.equals(END)) {
                visited.add(node);
                printPath(visited);
                visited.removeLast();
                break;
            }
        }
        for (String node : nodes) {
            if (visited.contains(node) || node.equals(END)) {
                continue;
            }
            visited.addLast(node);
            depthFirst(graph, visited);
            visited.removeLast();
        }
    }

    private void printPath(LinkedList<String> visited) {
        for (String node : visited) {
            System.out.print(node);
            System.out.print(" ");
        }
        System.out.println();
    }
}

कार्यक्रम का आउटपुट:

B E 
B A C E 
B A C F E 
B F E 
B F C E 

5
कृपया ध्यान दें कि यह एक चौड़ाई-पहला ट्रैवर्सल नहीं है। चौड़ाई के साथ पहले आप पहले सभी नोड्स की दूरी 0 से रूट पर जाएँ, फिर उन दूरी 1, फिर 2, आदि के साथ
mweerden

14
सही है, यह एक डीएफएस है। एक बीएफएस को सभी स्तर-एन नोड्स के बाद संसाधित किए जाने वाले स्तर, (एन + 1) नोड्स के लिए एक कतार का उपयोग करने की आवश्यकता होगी । हालांकि, ओपी के उद्देश्यों के लिए, या तो बीएफएस या डीएफएस काम करेंगे, क्योंकि पथों का कोई पसंदीदा सॉर्टिंग क्रम निर्दिष्ट नहीं है।
मैट जे

1
केसी, मैं उम्र के लिए इस समस्या का हल ढूंढ रहा हूं। मैंने हाल ही में इस डीएफएस को सी ++ में लागू किया है और यह एक इलाज का काम करता है।
एंडीयुक

6
यदि आप गहरे ग्राफ (ए-> बी-> सी -> ...-> एन) होगा तो पुनरावृत्ति का नुकसान आप जावा में StackOverflowError हो सकता है।
Rrr

1
मैंने C # में एक पुनरावृत्त संस्करण जोड़ा है।
बटा

23

नेशनल इंस्टीट्यूट ऑफ स्टैंडर्ड एंड टेक्नोलॉजी (NIST) ऑनलाइन डिक्शनरी ऑफ अल्गोरिद्म एंड डेटा स्ट्रक्चर्स इस समस्या को " सभी सरल रास्तों" के रूप में सूचीबद्ध करता है और गहराई-पहली खोज की सिफारिश करता है । CLRS संबंधित एल्गोरिदम की आपूर्ति करता है।

पेट्री नेट का उपयोग करने वाली एक चतुर तकनीक यहां पाई जाती है


2
क्या आप एक बेहतर समाधान के साथ मेरी मदद कर सकते हैं? एक DFS को चलाने में हमेशा के लिए लगता है : stackoverflow.com/q/8342101/632951
Pacerier

ध्यान दें कि ग्राफ़ के साथ आना आसान है, जिसके लिए डीएफएस बहुत अक्षम है, भले ही दो नोड्स के बीच सभी सरल रास्तों का सेट छोटा और खोजने में आसान हो। उदाहरण के लिए, एक अप्रत्यक्ष ग्राफ़ पर विचार करें जहां शुरुआती नोड में दो पड़ोसी हैं: लक्ष्य नोड बी (जिसमें ए के अलावा कोई पड़ोसी नहीं है), और एक नोड सी जो पूरी तरह से n + 1 नोड के जुड़े हुए क्लिक्ट का हिस्सा है । वहाँ स्पष्ट रूप से एक से बी करने के लिए सिर्फ एक सरल मार्ग है हालांकि, एक भोला-भाला डीएफएस ओ (बर्बाद करेंगे n !) समय बेकार गुट की खोज। इसी तरह के उदाहरण (एक समाधान, डीएफएस घातीय समय लेता है) डीएजी के बीच भी पाया जा सकता है।
इल्मरी करोनें

एनआईएसटी कहता है: " गहराई-पहली खोज के साथ पथों की गणना की जा सकती है ।"
chomp

13

यहाँ वह pseudocode है जिसके साथ मैं आया था। यह कोई विशेष छद्म बोली नहीं है, लेकिन इसका पालन करने के लिए पर्याप्त सरल होना चाहिए।

कोई भी इसे अलग करना चाहता है।

  • [पी] वर्तमान पथ का प्रतिनिधित्व करने वाले कोने की एक सूची है।

  • [x] उन रास्तों की एक सूची है जहाँ मापदंड मिलते हैं

  • [s] स्रोत शीर्ष है

  • [d] गंतव्य शीर्ष है

  • [c] वर्तमान वर्टेक्स है (पाथफाइंड रूटीन के लिए तर्क)

मान लें कि आसन्न कोने (पंक्ति 6) को देखने के लिए एक कुशल तरीका है।

     1 पैथलिस्ट [पी]
     2 सूचीऑफपैथलिस्ट [x]
     3 वर्टेक्स [s], [d]

     4 पाथफाइंड (वर्टेक्स [c])
     5 सूची के अंतिम छोर पर [c] जोड़ें [p]
     प्रत्येक वर्टेक्स के लिए 6 [v] [सी] से सटे
     7 अगर [v] [d] के बराबर है तो
     8 [x] में सूची [पी] सहेजें
     9 एल्स इफ [v] सूची में नहीं है [p]
    10 पाथफाइंड ([v])
    11 अगला के लिए
    12 [पू] से पूंछ हटाएं
    13 वापसी

क्या आप कृपया चरण 11 और चरण 12
बोझा उपयोगकर्ता

लाइन 11 बस फॉरेस्ट लूप के साथ जाने वाले अंतिम ब्लॉक को दर्शाती है जो लाइन 6 पर शुरू होता है। लाइन 12 का अर्थ है कॉल करने वाले के लौटने से पहले पथ सूची के अंतिम तत्व को हटा देना।
रॉबर्ट ग्रोव्स

PathFind के लिए प्रारंभिक कॉल क्या है - क्या आप स्रोत के शीर्ष [s] में पास होते हैं?
Bozo उपयोगकर्ता

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

8

चूँकि इस उत्तर में दिया गया गैर-पुनरावर्ती डीएफएस कार्यान्वयन टूटा हुआ प्रतीत होता है, मुझे वह प्रदान करें जो वास्तव में काम करता है।

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

# a generator function to find all simple paths between two nodes in a
# graph, represented as a dictionary that maps nodes to their neighbors
def find_simple_paths(graph, start, end):
    visited = set()
    visited.add(start)

    nodestack = list()
    indexstack = list()
    current = start
    i = 0

    while True:
        # get a list of the neighbors of the current node
        neighbors = graph[current]

        # find the next unvisited neighbor of this node, if any
        while i < len(neighbors) and neighbors[i] in visited: i += 1

        if i >= len(neighbors):
            # we've reached the last neighbor of this node, backtrack
            visited.remove(current)
            if len(nodestack) < 1: break  # can't backtrack, stop!
            current = nodestack.pop()
            i = indexstack.pop()
        elif neighbors[i] == end:
            # yay, we found the target node! let the caller process the path
            yield nodestack + [current, end]
            i += 1
        else:
            # push current node and index onto stacks, switch to neighbor
            nodestack.append(current)
            indexstack.append(i+1)
            visited.add(neighbors[i])
            current = neighbors[i]
            i = 0

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

यह कोड एक अलग visitedसेट का भी उपयोग करता है , जिसमें हमेशा वर्तमान नोड और स्टैक पर कोई नोड होता है, मुझे कुशलतापूर्वक जांचने के लिए कि क्या नोड पहले से ही मौजूदा पथ का हिस्सा है। यदि आपकी भाषा में "ऑर्डर सेट" डेटा संरचना है जो दोनों कुशल स्टैक-जैसे पुश / पॉप संचालन और कुशल सदस्यता क्वेरी प्रदान करती है, तो आप नोड स्टैक के लिए उपयोग कर सकते हैं और अलग visitedसेट से छुटकारा पा सकते हैं ।

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

यहां कुछ परीक्षण कोड दर्शाए गए हैं कि ऊपर दिए गए फ़ंक्शन कैसे काम करते हैं:

# test graph:
#     ,---B---.
#     A   |   D
#     `---C---'
graph = {
    "A": ("B", "C"),
    "B": ("A", "C", "D"),
    "C": ("A", "B", "D"),
    "D": ("B", "C"),
}

# find paths from A to D
for path in find_simple_paths(graph, "A", "D"): print " -> ".join(path)

दिए गए उदाहरण ग्राफ पर इस कोड को चलाने से निम्न आउटपुट का उत्पादन होता है:

ए -> बी -> सी -> डी
ए -> बी -> डी
ए -> सी -> बी -> डी
ए -> सी -> डी

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


Ps।ऐसे ग्राफ़ बनाना आसान है जिनके लिए सरल खोज एल्गोरिदम इस तरह (और इस धागे में दिए गए अन्य) बहुत खराब प्रदर्शन करते हैं।

उदाहरण के लिए, एक अप्रत्यक्ष ग्राफ पर ए से बी तक के सभी रास्तों को खोजने के कार्य पर विचार करें, जहां शुरुआती नोड में दो पड़ोसी हैं: लक्ष्य नोड बी (जिसमें ए के अलावा कोई अन्य पड़ोसी नहीं है) और एक नोड सी जो एक गुट का हिस्सा है के एन +1 नोड्स, इस तरह:

graph = {
    "A": ("B", "C"),
    "B": ("A"),
    "C": ("A", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
    "D": ("C", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
    "E": ("C", "D", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
    "F": ("C", "D", "E", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
    "G": ("C", "D", "E", "F", "H", "I", "J", "K", "L", "M", "N", "O"),
    "H": ("C", "D", "E", "F", "G", "I", "J", "K", "L", "M", "N", "O"),
    "I": ("C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O"),
    "J": ("C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "O"),
    "K": ("C", "D", "E", "F", "G", "H", "I", "J", "L", "M", "N", "O"),
    "L": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "M", "N", "O"),
    "M": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "N", "O"),
    "N": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "O"),
    "O": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"),
}

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

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

बेशक, लक्ष्य नोड B के एक छोर को Clique (C के अलावा अन्य) में से एक या DAG की अंतिम परत से जोड़कर, A से B तक के संभावित रास्तों की एक बड़ी संख्या का निर्माण होगा , और एक विशुद्ध रूप से स्थानीय खोज एल्गोरिथ्म वास्तव में पहले से नहीं बता सकता है कि यह इस तरह का एक किनारा मिलेगा या नहीं। इस प्रकार, एक अर्थ में, ऐसी भोली खोजों की खराब आउटपुट संवेदनशीलता उनके ग्राफ की वैश्विक संरचना के बारे में जागरूकता की कमी के कारण है।

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


1
यही मैं देख रहा हूँ, धन्यवाद :) :)
arslan

आपके DFS गैर-पुनरावर्ती समाधान के लिए धन्यवाद। बस ध्यान दें कि अंतिम छपाई के लिए परिणाम में एक सिंटैक्स त्रुटि है, होना चाहिए for path in find_simple_paths(graph, "A", "D"): print(" -> ".join(path)), printकोष्ठक गायब था।
डेविड ओलिवान उबिएटो

1
@ DavidOlivánUbieto: यह पायथन 2 कोड है, इसीलिए कोई कोष्ठक नहीं है। :)
इल्मरी करोनें

5

यहां दूसरी मंजिल की तुलना में तार्किक रूप से बेहतर दिखने वाला पुनरावर्ती संस्करण है।

public class Search {

private static final String START = "B";
private static final String END = "E";

public static void main(String[] args) {
    // this graph is directional
    Graph graph = new Graph();
    graph.addEdge("A", "B");
    graph.addEdge("A", "C");
    graph.addEdge("B", "A");
    graph.addEdge("B", "D");
    graph.addEdge("B", "E"); // this is the only one-way connection
    graph.addEdge("B", "F");
    graph.addEdge("C", "A");
    graph.addEdge("C", "E");
    graph.addEdge("C", "F");
    graph.addEdge("D", "B");
    graph.addEdge("E", "C");
    graph.addEdge("E", "F");
    graph.addEdge("F", "B");
    graph.addEdge("F", "C");
    graph.addEdge("F", "E");
    List<ArrayList<String>> paths = new ArrayList<ArrayList<String>>();
    String currentNode = START;
    List<String> visited = new ArrayList<String>();
    visited.add(START);
    new Search().findAllPaths(graph, seen, paths, currentNode);
    for(ArrayList<String> path : paths){
        for (String node : path) {
            System.out.print(node);
            System.out.print(" ");
        }
        System.out.println();
    }   
}

private void findAllPaths(Graph graph, List<String> visited, List<ArrayList<String>> paths, String currentNode) {        
    if (currentNode.equals(END)) { 
        paths.add(new ArrayList(Arrays.asList(visited.toArray())));
        return;
    }
    else {
        LinkedList<String> nodes = graph.adjacentNodes(currentNode);    
        for (String node : nodes) {
            if (visited.contains(node)) {
                continue;
            } 
            List<String> temp = new ArrayList<String>();
            temp.addAll(visited);
            temp.add(node);          
            findAllPaths(graph, temp, paths, node);
        }
    }
}
}

प्रोग्राम आउटपुट

B A C E 

B A C F E 

B E

B F C E

B F E 

4

सी कोड में समाधान। यह DFS पर आधारित है जो न्यूनतम मेमोरी का उपयोग करता है।

#include <stdio.h>
#include <stdbool.h>

#define maxN    20  

struct  nodeLink
{

    char node1;
    char node2;

};

struct  stack
{   
    int sp;
    char    node[maxN];
};   

void    initStk(stk)
struct  stack   *stk;
{
    int i;
    for (i = 0; i < maxN; i++)
        stk->node[i] = ' ';
    stk->sp = -1;   
}

void    pushIn(stk, node)
struct  stack   *stk;
char    node;
{

    stk->sp++;
    stk->node[stk->sp] = node;

}    

void    popOutAll(stk)
struct  stack   *stk;
{

    char    node;
    int i, stkN = stk->sp;

    for (i = 0; i <= stkN; i++)
    {
        node = stk->node[i];
        if (i == 0)
            printf("src node : %c", node);
        else if (i == stkN)
            printf(" => %c : dst node.\n", node);
        else
            printf(" => %c ", node);
    }

}


/* Test whether the node already exists in the stack    */
bool    InStack(stk, InterN)
struct  stack   *stk;
char    InterN;
{

    int i, stkN = stk->sp;  /* 0-based  */
    bool    rtn = false;    

    for (i = 0; i <= stkN; i++)
    {
        if (stk->node[i] == InterN)
        {
            rtn = true;
            break;
        }
    }

    return     rtn;

}

char    otherNode(targetNode, lnkNode)
char    targetNode;
struct  nodeLink    *lnkNode;
{

    return  (lnkNode->node1 == targetNode) ? lnkNode->node2 : lnkNode->node1;

}

int entries = 8;
struct  nodeLink    topo[maxN]    =       
    {
        {'b', 'a'}, 
        {'b', 'e'}, 
        {'b', 'd'}, 
        {'f', 'b'}, 
        {'a', 'c'},
        {'c', 'f'}, 
        {'c', 'e'},
        {'f', 'e'},               
    };

char    srcNode = 'b', dstN = 'e';      

int reachTime;  

void    InterNode(interN, stk)
char    interN;
struct  stack   *stk;
{

    char    otherInterN;
    int i, numInterN = 0;
    static  int entryTime   =   0;

    entryTime++;

    for (i = 0; i < entries; i++)
    {

        if (topo[i].node1 != interN  && topo[i].node2 != interN) 
        {
            continue;   
        }

        otherInterN = otherNode(interN, &topo[i]);

        numInterN++;

        if (otherInterN == stk->node[stk->sp - 1])
        {
            continue;   
        }

        /*  Loop avoidance: abandon the route   */
        if (InStack(stk, otherInterN) == true)
        {
            continue;   
        }

        pushIn(stk, otherInterN);

        if (otherInterN == dstN)
        {
            popOutAll(stk);
            reachTime++;
            stk->sp --;   /*    back trace one node  */
            continue;
        }
        else
            InterNode(otherInterN, stk);

    }

        stk->sp --;

}


int    main()

{

    struct  stack   stk;

    initStk(&stk);
    pushIn(&stk, srcNode);  

    reachTime = 0;
    InterNode(srcNode, &stk);

    printf("\nNumber of all possible and unique routes = %d\n", reachTime);

}

2

यह देर हो सकती है, लेकिन यहां जावा से डीएफएस एल्गोरिथ्म का एक ही सी # संस्करण है, जो केसी से जावा में एक स्टैक का उपयोग करते हुए दो नोड्स के बीच सभी रास्तों के लिए पार करने के लिए है। हमेशा की तरह पुनरावर्ती के साथ पठनीयता बेहतर है।

    void DepthFirstIterative(T start, T endNode)
    {
        var visited = new LinkedList<T>();
        var stack = new Stack<T>();

        stack.Push(start);

        while (stack.Count != 0)
        {
            var current = stack.Pop();

            if (visited.Contains(current))
                continue;

            visited.AddLast(current);

            var neighbours = AdjacentNodes(current);

            foreach (var neighbour in neighbours)
            {
                if (visited.Contains(neighbour))
                    continue;

                if (neighbour.Equals(endNode))
                {
                    visited.AddLast(neighbour);
                    printPath(visited));
                    visited.RemoveLast();
                    break;
                }
            }

            bool isPushed = false;
            foreach (var neighbour in neighbours.Reverse())
            {
                if (neighbour.Equals(endNode) || visited.Contains(neighbour) || stack.Contains(neighbour))
                {
                    continue;
                }

                isPushed = true;
                stack.Push(neighbour);
            }

            if (!isPushed)
                visited.RemoveLast();
        }
    }
यह परीक्षण करने के लिए एक नमूना ग्राफ है:

    // नमूना ग्राफ। नंबर एज आइडी हैं
    // 1 3       
    // ए --- बी --- सी ----
    // | | 2 |
    // | 4 ----- डी |
    // ------------------

1
उत्कृष्ट - आपने स्टैक-आधारित पुनरावृत्ति के साथ पुनरावृत्ति को कैसे प्रतिस्थापित किया।
सिद्धार्थ घोष

मुझे अभी भी यह समझ में नहीं आ रहा है, क्या है neighbours.Reverse()? क्या यह है List<T>.Reverse ?

मैंने इस गैर-पुनरावर्ती संस्करण की जाँच की, लेकिन यह सही नहीं लगता है। पुनरावर्ती संस्करण ठीक है। शायद गैर-पुनरावर्ती में बदल जाने पर, एक छोटी सी गलती हो जाती है
arslan

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

@llmari Karonen, Nice, मैं जाँच करने जा रहा हूँ, बढ़िया काम।
अरसलान

1

मैंने हाल ही में इसी तरह की समस्या को हल किया है, सभी समाधानों के बजाय मुझे केवल सबसे छोटी में दिलचस्पी थी।

मैंने 'चौड़ाई पहले' पुनरावृति खोज का उपयोग किया था, जिसमें से प्रत्येक ने स्थिति की एक कतार का उपयोग किया था, जिसमें ग्राफ पर एक वर्तमान बिंदु और वहां पहुंचने के लिए लिए गए पथ पर एक रिकॉर्ड था।

आप कतार में एक एकल रिकॉर्ड के साथ शुरू करते हैं, जिसमें शुरुआती नोड और एक खाली रास्ता है।

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

अब, आप कुछ इसी तरह का उपयोग कर सकते हैं, लेकिन जब आप कोई समाधान ढूंढते हैं, तो रोकने के बजाय उस समाधान को अपनी 'मिली सूची' में जोड़ें और जारी रखें।

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

यदि आप थोड़ा और छद्मकोड चाहते हैं एक टिप्पणी या कुछ पोस्ट करें, और मैं विस्तृत करूंगा।


6
मेरा मानना ​​है कि यदि आप केवल सबसे छोटे रास्ते में रुचि रखते हैं, तो दिज्क्स्ट्रा का एल्गोरिथम "समाधान" है :)।
vicatcu

1

मुझे लगता है कि आपको इसके पीछे अपनी वास्तविक समस्या का वर्णन करना चाहिए। मैं यह कहता हूं क्योंकि आप कुछ समय के लिए कुशल पूछते हैं, फिर भी समस्या का जवाब तेजी से बढ़ता है!

इसलिए मैं कुछ घातीय की तुलना में एक बेहतर एल्गोरिथ्म की उम्मीद नहीं करूंगा।

मैं बैकग्रांउड करूंगा और पूरे ग्राफ पर जाऊंगा। चक्र से बचने के लिए, रास्ते में आने वाले सभी नोड्स को बचाएं। जब आप वापस जाएं, तो नोड को चिह्नित करें।

पुनरावर्तन का उपयोग करना:

static bool[] visited;//all false
Stack<int> currentway; initialize empty

function findnodes(int nextnode)
{
if (nextnode==destnode)
{
  print currentway 
  return;
}
visited[nextnode]=true;
Push nextnode to the end of currentway.
for each node n accesible from nextnode:
  findnodes(n);
visited[nextnode]=false; 
pop from currenteay
}

या यह गलत है?

संपादित करें: ओह, और मैं भूल गया: आपको उस नोड स्टैक का उपयोग करके पुनरावर्ती कॉल को समाप्त करना चाहिए


मेरी वास्तविक समस्या ठीक वैसी ही है जैसा मैंने वर्णित किया है, केवल बहुत बड़े सेटों के साथ। मैं मानता हूं कि यह सेट के आकार के साथ तेजी से बढ़ता है।
रॉबर्ट ग्रोव्स

1

मूल सिद्धांत आपको ग्राफ़िक्स के बारे में चिंता करने की आवश्यकता नहीं है। यह मानक समस्या है जिसे डायनेमिक कनेक्टिविटी समस्या के रूप में जाना जाता है। निम्न प्रकार के तरीके हैं जिनसे आप नोड प्राप्त कर सकते हैं जुड़े हुए हैं या नहीं:

  1. जल्दी खोजें
  2. त्वरित संघ
  3. बेहतर एल्गोरिथम (दोनों का संयोजन)

यहाँ द सी कोड है जिसे मैंने न्यूनतम समय जटिलता ओ (लॉग * एन) के साथ आज़माया है, जिसका अर्थ है कि 65536 किनारों की सूची के लिए, इसे 4 खोज की आवश्यकता है और 2 ^ 65536 के लिए, इसे 5 खोज की आवश्यकता है। मैं एल्गोरिदम से अपना कार्यान्वयन साझा कर रहा हूं: प्रिंसटन विश्वविद्यालय से एल्गोरिथम पाठ्यक्रम

टीआईपी: आप उचित स्पष्टीकरण के साथ ऊपर दिए गए लिंक से जावा समाधान पा सकते हैं।

/* Checking Connection Between Two Edges */

#include<stdio.h>
#include<stdlib.h>
#define MAX 100

/*
  Data structure used

vertex[] - used to Store The vertices
size - No. of vertices
sz[] - size of child's
*/

/*Function Declaration */
void initalize(int *vertex, int *sz, int size);
int root(int *vertex, int i);
void add(int *vertex, int *sz, int p, int q);
int connected(int *vertex, int p, int q);

int main() //Main Function
{ 
char filename[50], ch, ch1[MAX];
int temp = 0, *vertex, first = 0, node1, node2, size = 0, *sz;
FILE *fp;


printf("Enter the filename - "); //Accept File Name
scanf("%s", filename);
fp = fopen(filename, "r");
if (fp == NULL)
{
    printf("File does not exist");
    exit(1);
}
while (1)
{
    if (first == 0) //getting no. of vertices
    {
        ch = getc(fp);
        if (temp == 0)
        {
            fseek(fp, -1, 1);
            fscanf(fp, "%s", &ch1);
            fseek(fp, 1, 1);
            temp = 1;
        }
        if (isdigit(ch))
        {
            size = atoi(ch1);
            vertex = (int*) malloc(size * sizeof(int));     //dynamically allocate size  
            sz = (int*) malloc(size * sizeof(int));
            initalize(vertex, sz, size);        //initialization of vertex[] and sz[]
        }
        if (ch == '\n')
        {
            first = 1;
            temp = 0;
        }
    }
    else
    {
        ch = fgetc(fp);
        if (isdigit(ch))
            temp = temp * 10 + (ch - 48);   //calculating value from ch
        else
        {
            /* Validating the file  */

            if (ch != ',' && ch != '\n' && ch != EOF)
            {
                printf("\n\nUnkwown Character Detected.. Exiting..!");

                exit(1);
            }
            if (ch == ',')
                node1 = temp;
            else
            {
                node2 = temp;
                printf("\n\n%d\t%d", node1, node2);
                if (node1 > node2)
                {
                    temp = node1;
                    node1 = node2;
                    node2 = temp;
                }

                /* Adding the input nodes */

                if (!connected(vertex, node1, node2))
                    add(vertex, sz, node1, node2);
            }
            temp = 0;
        }

        if (ch == EOF)
        {
            fclose(fp);
            break;
        }
    }
}

do
{
    printf("\n\n==== check if connected ===");
    printf("\nEnter First Vertex:");
    scanf("%d", &node1);
    printf("\nEnter Second Vertex:");
    scanf("%d", &node2);

    /* Validating The Input */

    if( node1 > size || node2 > size )
    {
        printf("\n\n Invalid Node Value..");
        break;
    }

    /* Checking the connectivity of nodes */

    if (connected(vertex, node1, node2))
        printf("Vertex %d and %d are Connected..!", node1, node2);
    else
        printf("Vertex %d and %d are Not Connected..!", node1, node2);


    printf("\n 0/1:  ");

    scanf("%d", &temp);

} while (temp != 0);

free((void*) vertex);
free((void*) sz);


return 0;
}

void initalize(int *vertex, int *sz, int size) //Initialization of graph
{
int i;
for (i = 0; i < size; i++)
{
    vertex[i] = i;
    sz[i] = 0;
}
}
int root(int *vertex, int i)    //obtaining the root
{
while (i != vertex[i])
{
    vertex[i] = vertex[vertex[i]];
    i = vertex[i];
}
return i;
}

/* Time Complexity for Add --> logn */
void add(int *vertex, int *sz, int p, int q) //Adding of node
{
int i, j;
i = root(vertex, p);
j = root(vertex, q);

/* Adding small subtree in large subtree  */

if (sz[i] < sz[j])
{
    vertex[i] = j;
    sz[j] += sz[i];
}
else
{
    vertex[j] = i;
    sz[i] += sz[j];
}

}

/* Time Complexity for Search -->lg* n */

int connected(int *vertex, int p, int q) //Checking of  connectivity of nodes
{
/* Checking if root is same  */

if (root(vertex, p) == root(vertex, q))
    return 1;

return 0;
}

यह समस्या को हल करने के लिए प्रतीत नहीं होता है। ओपी दो नोड्स के बीच सभी सरल रास्तों को खोजना चाहता है, न कि केवल यह जांचने के लिए कि क्या कोई रास्ता मौजूद है।
इल्मरी करोनें

1

find_paths [s, t, d, k]

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

मैं व्यक्तिगत रूप से find_paths[s, t, d, k]उपयोगी फॉर्म का एक एल्गोरिथ्म ढूंढता हूं , जहां:

  • s शुरुआती नोड है
  • t लक्ष्य नोड है
  • डी खोज करने के लिए अधिकतम गहराई है
  • k, खोजने के लिए पथों की संख्या है

के लिए अपनी प्रोग्रामिंग भाषा के अनन्तता के रूप का उपयोग करना dऔर kआपको सभी पथ प्रदान करेगा।

§ जाहिर है कि अगर आप एक निर्देशित ग्राफ का उपयोग कर रहे हैं और आप चाहते हैं कि सभी के बीच अप्रत्यक्ष रास्ते हों sऔर tआपको यह दोनों तरीके चलाने होंगे:

find_paths[s, t, d, k] <join> find_paths[t, s, d, k]

हेल्पर फंक्शन

मुझे व्यक्तिगत रूप से पुनरावृत्ति पसंद है, हालांकि यह कुछ समय मुश्किल हो सकता है, वैसे भी पहले हमारे सहायक फ़ंक्शन को परिभाषित करने देता है:

def find_paths_recursion(graph, current, goal, current_depth, max_depth, num_paths, current_path, paths_found)
  current_path.append(current)

  if current_depth > max_depth:
    return

  if current == goal:
    if len(paths_found) <= number_of_paths_to_find:
      paths_found.append(copy(current_path))

    current_path.pop()
    return

  else:
    for successor in graph[current]:
    self.find_paths_recursion(graph, successor, goal, current_depth + 1, max_depth, num_paths, current_path, paths_found)

  current_path.pop()

मुख्य कार्य

उस रास्ते से बाहर निकलने के साथ, मुख्य कार्य तुच्छ है:

def find_paths[s, t, d, k]:
  paths_found = [] # PASSING THIS BY REFERENCE  
  find_paths_recursion(s, t, 0, d, k, [], paths_found)

सबसे पहले, कुछ चीज़ों पर ध्यान दें:

  • उपरोक्त छद्म कोड भाषाओं का मैश-अप है - लेकिन सबसे दृढ़ता से मिलता-जुलता अजगर है (क्योंकि मैं इसमें सिर्फ कोडिंग कर रहा था)। एक सख्त कॉपी-पेस्ट से काम नहीं चलेगा।
  • [] एक गैर-सूचीबद्ध सूची है, इसे अपनी पसंद की प्रोग्रामिंग भाषा के लिए समकक्ष के साथ बदलें
  • paths_foundसंदर्भ द्वारा पारित किया गया है । यह स्पष्ट है कि पुनरावृत्ति फ़ंक्शन कुछ भी वापस नहीं करता है। इसे उचित रूप से संभालें।
  • यहाँ संरचना के graphकुछ रूप मान रहा है hashed। एक ग्राफ को लागू करने के तरीकों की अधिकता है। किसी भी तरह से, graph[vertex]आप एक निर्देशित ग्राफ में आसन्न कोने की एक सूची प्राप्त करता है - तदनुसार समायोजित करें।
  • यह मानता है कि आपने "बकल" (स्व-लूप), चक्र और बहु-किनारों को हटाने के लिए पूर्व-संसाधित किया है

0

यहाँ मेरे सिर के ऊपर एक विचार है:

  1. एक कनेक्शन खोजें। (गहराई-पहली खोज संभवतः इसके लिए एक अच्छा एल्गोरिथ्म है, क्योंकि पथ की लंबाई मायने नहीं रखती है।)
  2. अंतिम खंड को अक्षम करें।
  3. पहले अक्षम कनेक्शन से पहले अंतिम नोड से दूसरा कनेक्शन खोजने का प्रयास करें।
  4. गोटो 2 जब तक कोई और कनेक्शन न हो।

यह सामान्य रूप से काम नहीं करेगा: यह दो या दो से अधिक रास्तों के बीच एक ही अंतिम छोर के लिए काफी संभव है। आपकी विधि केवल ऐसे रास्तों में से एक को खोजेगी।
इल्मरी करोनें

0

जहां तक ​​मैं रयान फॉक्स ( 58343 , क्रिश्चियन ( 58444 ), और खुद को ( 58461 ) द्वारा दिए गए समाधानों के बारे में बता सकता हूं, जितना यह मिलता है उतना ही अच्छा है। मुझे विश्वास नहीं है कि इस मामले में चौड़ाई-पहला ट्रैवर्सल मदद करता है, जैसा कि आप करेंगे। नहीं किनारों के साथ सभी रास्ते मिलता है। उदाहरण के लिए, (A,B), (A,C), (B,C), (B,D)और (C,D)आप रास्तों मिल जाएगा ABDऔर ACDनहीं, बल्कि ABCD


mweerden, द ब्रेडथ-फर्स्ट ट्रैवर्सल जो मैंने प्रस्तुत किया था, किसी भी चक्र से बचने के दौरान सभी पथ पाएंगे। आपके द्वारा निर्दिष्ट ग्राफ़ के लिए, कार्यान्वयन तीनों पथों को सही ढंग से बताता है।
केसी वॉटसन

मैंने आपके कोड को पूरी तरह से नहीं पढ़ा था और मान लिया था कि आपने पहले-पहले ट्रैवर्सल का उपयोग किया है (क्योंकि आपने ऐसा कहा था)। हालांकि, आपकी टिप्पणी के बाद करीब से निरीक्षण करने पर, मैंने देखा कि यह वास्तव में नहीं है। यह वास्तव में रयान, क्रिश्चियन और रॉबर्ट की तरह एक स्मृतिहीन गहराई वाला पहला ट्रैवर्सल है।
स्वेदेन

0

मुझे उन सभी रास्तों को समाहित करने का एक तरीका मिला जिसमें अनंत शामिल हैं जिनमें छोरें हैं।

http://blog.vjeux.com/2009/project/project-shortest-path.html

परमाणु पथ और चक्र ढूँढना

Definition

हम जो करना चाहते हैं, वह बिंदु A से बिंदु B तक जाने वाले सभी संभावित रास्तों का पता लगाता है क्योंकि वहाँ चक्र शामिल हैं, आप बस से नहीं जा सकते और उन सभी की गणना कर सकते हैं। इसके बजाय, आपको परमाणु पथ ढूंढना होगा जो लूप नहीं करता है और सबसे छोटा संभव चक्र (आप अपने चक्र को खुद को दोहराना नहीं चाहते हैं)।

पहली परिभाषा मैंने परमाणु पथ की ली है जो एक ऐसा मार्ग है जो एक ही नोड से दो बार नहीं गुजरता है। हालांकि, मुझे पता चला कि सभी संभावनाएं नहीं थीं। कुछ परावर्तन के बाद, मुझे लगा कि नोड्स महत्वपूर्ण नहीं हैं, हालांकि किनारों हैं! तो एक परमाणु पथ एक ऐसा मार्ग है जो एक ही किनारे से दो बार नहीं गुजरता है।

यह परिभाषा आसान है, यह चक्रों के लिए भी काम करती है: बिंदु A का परमाणु चक्र एक परमाणु पथ है जो बिंदु A से जाता है और बिंदु A पर समाप्त होता है।

कार्यान्वयन

Atomic Paths A -> B

बिंदु A से शुरू होने वाले सभी मार्ग को प्राप्त करने के लिए, हम बिंदु A से पुनरावर्ती रूप से ग्राफ को पीछे करने जा रहे हैं। एक बच्चे के माध्यम से जाते हुए, हम एक लिंक बच्चे बनाने जा रहे हैं -> माता-पिता हम सभी किनारों को जानने के लिए पहले ही पार कर चुके हैं। इससे पहले कि हम उस बच्चे के पास जाएं, हमें उस लिंक की गई सूची का पता लगाना चाहिए और सुनिश्चित करना चाहिए कि निर्दिष्ट किनारे पहले से ही नहीं चला है।

जब हम गंतव्य बिंदु पर पहुंचते हैं, तो हम हमारे द्वारा प्राप्त पथ को संग्रहीत कर सकते हैं।

Freeing the list

समस्या तब होती है जब आप लिंक की गई सूची को मुक्त करना चाहते हैं। यह मूल रूप से एक पेड़ है जो रिवर्स ऑर्डर में जंजीर है। एक समाधान उस सूची को डबल-लिंक करना होगा और जब सभी परमाणु पथ मिल जाएंगे, तो पेड़ को शुरुआती बिंदु से मुक्त कर दें।

लेकिन एक चतुर समाधान एक संदर्भ गिनती (कचरा संग्रह से प्रेरित) का उपयोग करना है। हर बार जब आप एक माता-पिता के लिए एक लिंक जोड़ते हैं, तो आप इसकी संदर्भ संख्या में एक जोड़ते हैं। फिर, जब आप एक पथ के अंत में पहुंचते हैं, तो आप पीछे जाते हैं और मुक्त होते हैं जबकि संदर्भ संख्या 1 के बराबर होती है। यदि यह अधिक है, तो आप बस एक को हटा दें और रोक दें।

Atomic Cycle A

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

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

परमाणु पथ और चक्रों का मेल

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


यह पूछे गए प्रश्न का उत्तर नहीं देता है।
इल्मरी करोनें

0

जैसा कि कुछ अन्य पोस्टरों द्वारा वर्णित किया गया है, संक्षेप में समस्या यह है कि संचार अंत छोरों के बीच पथों के सभी संयोजनों के लिए ग्राफ को पुन: खोज करने के लिए गहराई-पहले खोज एल्गोरिदम का उपयोग किया जाता है।

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

खोज फिर पीछे हटती है, सबसे हाल के नोड पर लौटना अभी तक इसकी खोज नहीं हुई है।

मैंने इस विषय पर हाल ही में ब्लॉग किया, इस प्रक्रिया में एक उदाहरण C ++ कार्यान्वयन पोस्ट किया।


0

केसी वाटसन के जवाब में जोड़कर, यहां एक और जावा कार्यान्वयन है,। प्रारंभ नोड के साथ विज़िट किए गए नोड को प्रारंभ करना।

private void getPaths(Graph graph, LinkedList<String> visitedNodes) {
                LinkedList<String> adjacent = graph.getAdjacent(visitedNodes.getLast());
                for(String node : adjacent){
                    if(visitedNodes.contains(node)){
                        continue;
                    }
                    if(node.equals(END)){
                        visitedNodes.add(node);
                        printPath(visitedNodes);
                        visitedNodes.removeLast();
                    }
                    visitedNodes.add(node);
                    getPaths(graph, visitedNodes);
                    visitedNodes.removeLast();  
                }
            }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.