দুটি স্বেচ্ছাসেবীর ভার্টিসের মধ্যে সমস্ত সংযোগগুলি খুঁজে পেতে গ্রাফ অ্যালগরিদম


117

আমি নীচে বর্ণিত কাজটি সম্পাদন করার জন্য সেরা সময় দক্ষ অ্যালগরিদম নির্ধারণ করার চেষ্টা করছি।

আমার রেকর্ড একটি সেট আছে। রেকর্ডের এই সেটটির জন্য আমার কাছে সংযোগের ডেটা রয়েছে যা নির্দেশ করে যে কীভাবে এই সেট থেকে রেকর্ডের জোড়া জোড়া একে অপরের সাথে সংযুক্ত হয়। এটি মূলত একটি অপরিবর্তিত গ্রাফ উপস্থাপন করে, রেকর্ডগুলি শীর্ষে এবং সংযোগের ডেটাটি প্রান্ত হিসাবে with

সেটের সমস্ত রেকর্ডের সংযোগের তথ্য রয়েছে (যেমন কোনও অনাথ রেকর্ড উপস্থিত নেই; সেটে প্রতিটি রেকর্ড সেটে একটি বা একাধিক অন্যান্য রেকর্ডের সাথে সংযুক্ত থাকে)।

আমি সেট থেকে যে কোনও দুটি রেকর্ড বেছে নিতে চাই এবং নির্বাচিত রেকর্ডগুলির মধ্যে সমস্ত সহজ পাথ দেখাতে সক্ষম হতে চাই। "সহজ পাথ" দ্বারা আমি বোঝাচ্ছি যে পাথগুলিতে পাথের পুনরাবৃত্তি রেকর্ড নেই (কেবলমাত্র সীমাবদ্ধ পথ)।

দ্রষ্টব্য: দুটি নির্বাচিত রেকর্ড সর্বদা আলাদা হবে (অর্থাত্ শুরু এবং শেষ প্রান্তটি কখনই এক হবে না; কোনও চক্র থাকবে না)।

উদাহরণ স্বরূপ:

    আমার যদি নিম্নলিখিত রেকর্ড থাকে:
        এ, বি, সি, ডি, ই

    এবং নিম্নলিখিত সংযোগগুলি প্রতিনিধিত্ব করে: 
        (এ, বি), (এ, সি), (বি, ক), (বি, ডি), (বি, ই), (বি, এফ), (সি, ক), (সি, ই),
        (গ, এফ), (ডি, বি), (ই, সি), (ই, এফ), (এফ, বি), (এফ, সি), (এফ, ই)

        [যেখানে (এ, বি) এর অর্থ রেকর্ড এ এর ​​সাথে রেকর্ড সংযোগ স্থাপন করছে]

আমি যদি আমার শুরু রেকর্ড হিসাবে বি এবং ইটিকে আমার শেষ রেকর্ড হিসাবে বেছে নিই, তবে আমি রেকর্ড সংযোগের মাধ্যমে সমস্ত সহজ পাথ খুঁজে পেতে চাই যা রেকর্ড বি কে রেকর্ড করতে সংযোগ করবে would

   বি তে ই সংযোগকারী সমস্ত পথ:
      বি-> ই
      বি-> F-> ই
      বি-> F-> সি> ই
      বি-> a-> সি> ই
      বি-> a-> সি> F-> ই

এটি একটি উদাহরণ, বাস্তবে আমার কাছে কয়েক হাজার রেকর্ড রয়েছে এমন সেট থাকতে পারে।


সংযোগগুলি চক্র বলা হয় , এবং এই উত্তরটি আপনার জন্য প্রচুর তথ্য রয়েছে।
এলহোম

3
আপনি লুপ-মুক্ত সংযোগগুলির একটি সীমাবদ্ধ তালিকা চান বা সমস্ত সম্ভাব্য লুপের সাথে সংযোগের অসীম স্ট্রিম চান কিনা দয়া করে বলুন। Cf. ব্লারগবার্ডের উত্তর।
চার্লস স্টুয়ার্ট

যে কেউ এই ব্যাপারে সাহায্য করতে পারেন ??? stackoverflow.com/questions/32516706/...
tejas3006

উত্তর:


116

এটি গ্রাফের গভীরতা-প্রথম অনুসন্ধানের মাধ্যমে সম্পন্ন করা যায় বলে মনে হয়। গভীরতা-প্রথম অনুসন্ধানটি দুটি নোডের মধ্যে সমস্ত চক্রবিহীন পথ খুঁজে পাবে। এই অ্যালগরিদমটি খুব দ্রুত এবং বৃহত গ্রাফের স্কেল হওয়া উচিত (গ্রাফের ডেটা কাঠামোটি বিচ্ছিন্ন তাই এটি কেবল যতটা মেমরি প্রয়োজন তেমন ব্যবহার করে)।

আমি লক্ষ্য করেছি যে আপনি উল্লিখিত গ্রাফের কেবলমাত্র একটি প্রান্ত রয়েছে যা দিকনির্দেশক (বি, ই)। এটি কি টাইপ ছিল নাকি এটি সত্যই কোনও নির্দেশিত গ্রাফ ছিল? এই সমাধান নির্বিশেষে কাজ করে। দুঃখিত আমি সি তে এটি করতে অক্ষম ছিলাম, আমি সেই অঞ্চলে কিছুটা দুর্বল। আমি আশা করি আপনি খুব বেশি ঝামেলা ছাড়াই এই জাভা কোডটি অনুবাদ করতে সক্ষম হবেন।

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
কেসি, আমি যুগ যুগ ধরে এই সমস্যার সমাধান খুঁজছিলাম। আমি সম্প্রতি সি ++ এ এই ডিএফএস প্রয়োগ করেছি এবং এটি একটি ট্রিট কাজ করে।
AndyUK

6
পুনরাবৃত্তির অসুবিধা হ'ল যদি আপনার কাছে গভীর গ্রাফ থাকে (এ-> বি-> সি -> ...-> এন) আপনার জাভাতে স্ট্যাকওভারফ্লো এরিয়ার থাকতে পারে।
Rrr

1
আমি নীচে সি # তে একটি পুনরাবৃত্তি সংস্করণ যুক্ত করেছি।
বাট্টা

23

ন্যাশনাল ইনস্টিটিউট অফ স্ট্যান্ডার্ডস অ্যান্ড টেকনোলজি (এনআইএসটি) অ্যালগরিদম এবং ডেটা স্ট্রাকচারের অনলাইন অভিধান এই সমস্যাটিকে " সমস্ত সহজ পাথ" হিসাবে তালিকাভুক্ত করে এবং গভীরতার প্রথম অনুসন্ধানের পরামর্শ দেয় । সিএলআরএস প্রাসঙ্গিক আলগোরিদিম সরবরাহ করে।

পেট্রি নেট ব্যবহার করে একটি চতুর কৌশল এখানে পাওয়া যায়


2
আপনি কি আরও ভাল সমাধানে আমাকে সাহায্য করতে পারেন? একটি DFS লাগে সব সময় প্রবেশ করুন : চালানোর জন্য stackoverflow.com/q/8342101/632951
Pacerier

মনে রাখবেন যে দুটি নোডের মধ্যে সমস্ত সহজ পাথের সেট ছোট এবং সহজে খুঁজে পাওয়া সত্ত্বেও, গ্রাফগুলি নিয়ে আসা খুব সহজ যার জন্য ডিএফএস খুব অদক্ষ। উদাহরণস্বরূপ, একটি অপ্রচলিত গ্রাফটি বিবেচনা করুন যেখানে প্রারম্ভিক নোড এ এর ​​দুটি প্রতিবেশী রয়েছে: লক্ষ্য নোড বি (যার A ছাড়া অন্য কোনও প্রতিবেশী নেই), এবং একটি নোড সি যা এন + 1 নোডের সম্পূর্ণ সংযুক্ত চক্রের অংশ । যদিও এ থেকে বি পর্যন্ত স্পষ্টভাবে কেবল একটি সহজ পাথ আছে, একটি নির্দোষ ডিএফএস চক্রের অন্বেষণে ও ( এন !) সময় অপচয় করবে । অনুরূপ উদাহরণ (একটি সমাধান, ডিএফএস তাত্পর্যপূর্ণ সময় নেয়) ডিএজিএসের মধ্যেও পাওয়া যায়।
ইলমারি করোনেন

এনআইএসটি বলে: " গভীরতা-প্রথম অনুসন্ধানের সাথে পাথগুলি গণনা করা যেতে পারে ।"
chomp

13

এখানে আমি সিউডোকোড নিয়ে এসেছি। এটি কোনও বিশেষ সিউডোকোড উপভাষা নয়, তবে এটি অনুসরণ করার জন্য যথেষ্ট সহজ হওয়া উচিত।

যে কেউ এটিকে আলাদা করতে চান।

  • [p] হ'ল বর্তমান পথের প্রতিনিধিত্বকারী উল্লম্বের একটি তালিকা।

  • [x] এমন একটি পাথের তালিকা যেখানে মানদণ্ডগুলি পূরণ হয়

  • [গুলি] হ'ল উত্স শীর্ষে x

  • [d] গন্তব্য প্রান্তিক

  • [সি] হ'ল বর্তমান ভার্টেক্স (প্যাথফাইন্ড রুটিনের পক্ষে যুক্তি)

ধরুন পার্শ্ববর্তী শীর্ষগুলি (লাইন 6) সন্ধান করার জন্য একটি কার্যকর উপায় রয়েছে।

     1 পাথলিস্ট [পি]
     2 তালিকার অফপথ তালিকা [এক্স]
     3 ভার্টেক্স [গুলি], [d]

     4 পাথফাইন্ড (ভার্টেক্স [সি])
     5 তালিকার শেষ প্রান্তে [সি] যুক্ত করুন [পি]
     Each [সি] সংলগ্ন প্রতিটি ভার্টেক্স [v] এর জন্য
     7 যদি [v] সমান হয় তবে [d]
     [এক্স] এ 8 টি তালিকা সংরক্ষণ করুন
     9 অন্যথায় যদি [ভি] তালিকায় না থাকে [পি]
    10 টি প্যাথফাইন্ড ([v])
    11 পরবর্তী জন্য
    [পি] থেকে লেজ সরান
    13 রিটার্ন

আপনি কি দয়া করে পদক্ষেপ 11 এবং 12 ধাপে কিছুটা হালকা করে দিতে পারেন
বোজো ব্যবহারকারী

লাইন 11 কেবল শেষ প্রান্তটিকে বোঝায় যা লাইন 6-এ শুরু হয় লুপের সাথে যায় 12 লাইন 12 এর অর্থ কলারে ফিরে যাওয়ার আগে পথের তালিকার শেষ উপাদানটি সরিয়ে ফেলা।
রবার্ট গ্রোভস

পাথফাইন্ডের প্রাথমিক কলটি কী - আপনি উত্সের শীর্ষবিন্দুতে প্রবেশ করেন?
বোজো ব্যবহারকারী

এই উদাহরণে হ্যাঁ, তবে মনে রাখবেন যে আপনি এই সিউডোকোডের সাহায্যে একের পর এক মানচিত্রের বাস্তব কোডটি লিখতে চান না। এর অর্থ আরও ভালভাবে ডিজাইন করা কোডের চেয়ে কোনও চিন্তার প্রক্রিয়াটি বর্ণনা করা।
রবার্ট গ্রোভস

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সেট থেকে মুক্তি পেতে পারেন ।

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

উপরোক্ত প্রদত্ত ফাংশনটি কীভাবে কাজ করে তা এখানে দেখানোর জন্য এখানে কিছু টেস্ট কোড রয়েছে:

# 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) ব্যতীত একই আউটপুট পাওয়া যায় , যা আর সম্ভব নয়।


পুনশ্চ. গ্রাফগুলি তৈরি করা সহজ, যার জন্য এই জাতীয় সরল অনুসন্ধান অ্যালগরিদমগুলি (এবং এই থ্রেডে দেওয়া অন্যান্যগুলি) খুব খারাপভাবে সম্পাদন করে।

উদাহরণস্বরূপ, অপরিবর্তিত গ্রাফে A থেকে B পর্যন্ত সমস্ত পথ সন্ধানের কাজটি বিবেচনা করুন যেখানে শুরুর নোডের দু'টি প্রতিবেশী রয়েছে: লক্ষ্য নোড বি (যার A ছাড়া অন্য কোনও প্রতিবেশী নেই) এবং একটি নোড সি যা একটি চক্রের অংশ এর মতো এন +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"),
}

এটি সহজেই দেখতে পাওয়া যায় যে এ এবং বি এর মধ্যে একমাত্র পথ হ'ল সরাসরি, তবে নোড এ থেকে শুরু হওয়া একটি নির্দোষ ডিএফএস চক্রের মধ্যে অনর্থকভাবে পথগুলি অন্বেষণ করার জন্য ও ( এন !) সময় নষ্ট করবে , যদিও এটি স্পষ্টভাবেই (মানুষের কাছে) স্পষ্ট যে এই পাথগুলির কোনওটিই সম্ভবত বি-তে যেতে পারে না

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

অবশ্যই, চক্রের নোডগুলির মধ্যে একটি (সি ব্যতীত) বা ডাগের শেষ স্তর থেকে লক্ষ্য নোড বিতে একটি প্রান্ত যুক্ত করা এ, বি থেকে বিস্তৃত সংখ্যক সম্ভাব্য পথ তৈরি করবে এবং একটি বিশুদ্ধরূপে স্থানীয় অনুসন্ধান অ্যালগরিদম সত্যিই আগে থেকে বলতে পারে না যে এটি এর প্রান্তটি খুঁজে পাবে কিনা। সুতরাং, এক অর্থে, এই ধরনের নির্লজ্জ অনুসন্ধানগুলির দুর্বল আউটপুট সংবেদনশীলতা গ্রাফের বৈশ্বিক কাঠামো সম্পর্কে তাদের সচেতনতার অভাবের কারণ।

যদিও বিভিন্ন প্রাক-প্রসেসিং পদ্ধতি রয়েছে (যেমন পুনরায় পাতার নোডগুলি মুছে ফেলা, একক নোড ভারটেক্স বিভাজকগুলি অনুসন্ধান করা ইত্যাদি) যা এই "ক্ষতিকারক-সময় মৃত প্রান্তগুলি" এড়াতে ব্যবহার করা যেতে পারে, আমি কোনও জেনারেল সম্পর্কে জানি না প্রিপ্রোসেসিং ট্রিক যা তাদের সকল ক্ষেত্রেই দূর করতে পারে । একটি সাধারণ সমাধান হ'ল লক্ষ্য নোডটি এখনও পৌঁছনীয় (উপ-অনুসন্ধান ব্যবহার করে) এবং ব্যাকট্র্যাকটি যদি তা না হয় তবে তাড়াতাড়ি অনুসন্ধানের প্রতিটি ধাপে পরীক্ষা করা হবে - তবে হায় আফসোস, অনুসন্ধানটি উল্লেখযোগ্যভাবে কমিয়ে দেবে (সবচেয়ে খারাপভাবে) , গ্রাফের আকারের সাথে আনুপাতিকভাবে) এমন অনেকগুলি গ্রাফের জন্য যা এ জাতীয় রোগতাত্ত্বিক মৃত প্রান্তগুলি ধারণ করে না


1
এটি আমি অনুসন্ধান করছি, আপনাকে ধন্যবাদ :)
আর্সলান

আপনার ডিএফএস অ-পুনরাবৃত্ত সমাধানের জন্য আপনাকে ধন্যবাদ। কেবলমাত্র নোট করুন যে ফলাফলটি মুদ্রণের ফলে ফলাফলটি একটি সিনট্যাক্স ত্রুটি রয়েছে, হওয়া উচিত for path in find_simple_paths(graph, "A", "D"): print(" -> ".join(path)), এটি printপ্রথম বন্ধনী অনুপস্থিত ছিল।
ডেভিড অলিভান উবিটো

1
@ ডেভিডঅলিভানউবিটো: এটি পাইথন 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

সি কোডে সমাধান। এটি ডিএফএসের উপর ভিত্তি করে যা সর্বনিম্ন মেমরি ব্যবহার করে।

#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
দুর্দান্ত - আপনি কীভাবে স্ট্যাক-ভিত্তিক পুনরাবৃত্তির সাথে পুনরাবৃত্তিটি প্রতিস্থাপন করেছেন about
সিদ্ধার্থ ঘোষ

আমি এখনও বুঝতে পারি না, কী neighbours.Reverse()? এটা কি List<T>.Reverse ?

আমি এই পুনরাবৃত্ত সংস্করণটি চেক করেছি, তবে এটি সঠিক নয় বলে মনে হচ্ছে। পুনরাবৃত্ত সংস্করণ ঠিক আছে। হতে পারে যখন অ-রিকার্সভেজে পরিবর্তন করা হয়েছে, তখন একটি ছোট্ট ভুল হয়েছে
আর্সলান

@ আলেম: সম্মত, এই কোডটি কেবল ভেঙে গেছে। (ব্যাকট্র্যাকিংয়ের সময় এটি পরিদর্শন করা সেট থেকে নোডগুলি সঠিকভাবে সরিয়ে দেয় না এবং স্ট্যাক হ্যান্ডলিংটিও বিভ্রান্ত হয়েছে বলে মনে হয় it এটি ঠিক করা যায় কিনা তা দেখার চেষ্টা করেছি, তবে এটির জন্য মূলত একটি সম্পূর্ণ পুনর্লিখনের প্রয়োজন হবে)) আমি কেবল একটি সঠিক, কাজ করছে না এমন পুনরাবৃত্ত সমাধানের সাথে একটি উত্তর যুক্ত করেছে (পাইথনে, তবে এটি অন্য ভাষাগুলিতে পোর্ট করা অপেক্ষাকৃত সহজ হওয়া উচিত)।
ইলমারি করোনেন

@ লামারী করোনেন, খুব ভাল, আমি যাচ্ছি, দুর্দান্ত কাজ।
আর্সলান

1

আমি সম্প্রতি এটির মতো একটি সমস্যার সমাধান করেছি, সমস্ত সমাধানের পরিবর্তে আমি কেবলমাত্র সবচেয়ে কম আগ্রহী।

আমি একটি 'প্রস্থের প্রথম' পুনরাবৃত্ত অনুসন্ধানটি ব্যবহার করলাম যা স্থিতির সারি ব্যবহার করল 'যার প্রত্যেকটিতে গ্রাফের বর্তমান পয়েন্ট এবং সেখানে পৌঁছনোর জন্য যে পথটি রয়েছে তাতে একটি রেকর্ড ছিল।

আপনি কাতারে একক রেকর্ড দিয়ে শুরু করুন, যার প্রারম্ভিক নোড এবং খালি পথ রয়েছে।

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

এখন, আপনি অনুরূপ কিছু ব্যবহার করতে পারেন, কিন্তু আপনি যখন সমাধান খুঁজে পান, থামার পরিবর্তে, আপনার 'খুঁজে পাওয়া তালিকায়' সেই সমাধানটি যুক্ত করে চালিয়ে যান।

আপনাকে একটি পরিদর্শন করা নোডের তালিকার নজর রাখা দরকার, যাতে আপনি কখনই নিজের উপর ব্যাক ট্র্যাক না করে অন্যথায় আপনার অসীম লুপ থাকে।

আপনি যদি আরও কিছু সিউডোকোড চান তবে একটি মন্তব্য বা কিছু পোস্ট করুন এবং আমি বিশদভাবে জানাব।


6
আমি বিশ্বাস করি যদি আপনি কেবলমাত্র সবচেয়ে সংক্ষিপ্ত পথেই আগ্রহী হন, তবে ডিজকস্ট্রার অ্যালগোরিদম হল "সমাধান" :)।
ভিসাতচু

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
}

নাকি ভুল?

সম্পাদনা: ওহ, এবং আমি ভুলে গিয়েছি: আপনার নোড স্ট্যাকটি ব্যবহার করে পুনরাবৃত্ত কলগুলি অপসারণ করা উচিত


আমার আসল সমস্যাটি ঠিক যেমনটি আমি বর্ণনা করেছি ঠিক তেমন অনেক বড় সেট larger আমি সম্মত হই যে এটি সেট আকারের সাথে তাত্পর্যপূর্ণভাবে বৃদ্ধি পেতে পারে।
রবার্ট গ্রোভস

1

প্রাথমিক নীতিটি হ'ল গ্রাফগুলি সম্পর্কে আপনার চিন্তা করার দরকার নেই his এটি স্ট্যান্ডার্ড সমস্যাটি ডায়নামিক সংযোগ সমস্যা হিসাবে পরিচিত। নিম্নলিখিত ধরণের পদ্ধতি রয়েছে যা থেকে আপনি নোডগুলি সংযুক্ত আছেন কিনা তা অর্জন করতে পারেন:

  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]দরকারী বলে মনে করি যেখানে:

  • s হল নোডিং
  • t লক্ষ্য নোড
  • d অনুসন্ধানের সর্বাধিক গভীরতা
  • k হল পাথের সংখ্যা of

আপনার প্রোগ্রামিং ভাষার অনন্যতার রূপটি ব্যবহার করে 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)

প্রথমে কয়েকটি বিষয় লক্ষ্য করুন:

  • উপরের সিউডো কোডটি ভাষার একটি ম্যাশ-আপ - তবে সর্বাধিক দৃ strongly়ভাবে পাইথনের সাথে সাদৃশ্যপূর্ণ (যেহেতু আমি এটিতে কেবল কোডিং করছি)। একটি কঠোর অনুলিপি-পেস্ট কাজ করবে না।
  • [] একটি অবিচ্ছিন্ন তালিকা, এটি আপনার পছন্দসই প্রোগ্রামিং ভাষার সমতুল্য সাথে প্রতিস্থাপন করুন
  • paths_foundরেফারেন্স দ্বারা পাস করা হয় । এটি স্পষ্ট যে পুনরাবৃত্তি ফাংশন কোনও কিছুই ফেরায় না। এটি যথাযথভাবে পরিচালনা করুন।
  • এখানে কাঠামোর graphকিছু ফর্ম ধরে নেওয়া হচ্ছে hashed। গ্রাফ বাস্তবায়নের বিভিন্ন উপায় রয়েছে। যে কোনও উপায়ে, graph[vertex]আপনাকে নির্দেশিত গ্রাফের সাথে সংলগ্ন শীর্ষগুলির একটি তালিকা পেয়েছে - সেই অনুসারে সামঞ্জস্য করুন।
  • এটি ধরে নিয়েছে যে আপনি "বাকলস" (স্ব-লুপগুলি), চক্র এবং বহু-প্রান্তগুলি অপসারণ করতে প্রাক প্রক্রিয়া করেছেন

0

আমার মাথার উপরের দিক থেকে এখানে একটি চিন্তাভাবনা রয়েছে:

  1. একটি সংযোগ সন্ধান করুন। (গভীরতা-প্রথম অনুসন্ধান সম্ভবত এটির জন্য একটি ভাল অ্যালগরিদম, যেহেতু পথের দৈর্ঘ্য কোনও বিষয় নয়))
  2. শেষ বিভাগটি অক্ষম করুন।
  3. আগের অক্ষম সংযোগের আগে শেষ নোড থেকে অন্য কোনও সংযোগ খোঁজার চেষ্টা করুন।
  4. আর কোনও সংযোগ না পাওয়া পর্যন্ত 2 যান।

এটি সাধারণভাবে কাজ করবে না: উভয় বা তারও বেশি পথগুলির পক্ষে সমাপ্তি প্রান্তটি একই প্রান্তে থাকা বেশ সম্ভব। আপনার পদ্ধতিতে কেবল এই জাতীয় একটি পাথ খুঁজে পাওয়া যাবে।
ইলমারি করোনেন

0

যতদূর আমি রায়ান ফক্স ( 58343 , খ্রিস্টান ( 58444 ), এবং আপনি ( 58461 ) প্রদত্ত সমাধানগুলি যতটা পান ঠিক ততই বলতে পারেন I আমি বিশ্বাস করি না যে প্রস্থের প্রথম ট্র্যাভারসাল এই ক্ষেত্রে সহায়তা করে, আপনি যেমন করবেন না প্রান্ত সঙ্গে সব পাথ পেতে। উদাহরণস্বরূপ, (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 এর একটি পারমাণবিক চক্র হল একটি পারমাণবিক পথ যা বিন্দু A থেকে শেষ হয় এবং A বিন্দুতে শেষ হয় path

বাস্তবায়ন

Atomic Paths A -> B

বিন্দু A থেকে শুরু করে সমস্ত পাথ পেতে, আমরা পয়েন্ট এ থেকে ক্রমাগত গ্রাফটি অতিক্রম করতে যাচ্ছি একটি সন্তানের মধ্য দিয়ে যাওয়ার সময় আমরা সমস্ত প্রান্ত জানতে আমাদের একটি লিঙ্ক চাইল্ড -> পিতা বা মাতা তৈরি করতে যাচ্ছি ইতিমধ্যে পার হয়ে গেছে। আমরা সেই শিশুটির কাছে যাওয়ার আগে আমাদের অবশ্যই সেই লিঙ্কযুক্ত তালিকাটি অতিক্রম করতে হবে এবং নিশ্চিত করা উচিত যে নির্দিষ্ট প্রান্তটি ইতিমধ্যে পেরেছে।

আমরা যখন গন্তব্যস্থলে পৌঁছে যাই, আমরা যে পথটি পেয়েছি তা সংরক্ষণ করতে পারি।

Freeing the list

আপনি লিঙ্কযুক্ত তালিকাটি মুক্ত করতে চাইলে একটি সমস্যা দেখা দেয়। এটি মূলত বিপরীত ক্রমে বেঁধে রাখা গাছ। একটি সমাধান হ'ল সেই তালিকাটিকে ডাবল লিঙ্ক করা এবং যখন সমস্ত পারমাণবিক পাথ সন্ধান করা হবে তখন গাছটিকে প্রারম্ভিক বিন্দু থেকে মুক্ত করুন।

তবে একটি চতুর সমাধান হল একটি রেফারেন্স গণনা (আবর্জনা সংগ্রহ থেকে অনুপ্রাণিত) ব্যবহার করা। প্রতিবার আপনি যখন কোনও পিতামাতার সাথে একটি লিঙ্ক যুক্ত করেন আপনি তার রেফারেন্স গণনায় একটি যুক্ত করেন। তারপরে, আপনি যখন কোনও পাথ শেষে পৌঁছবেন, আপনি রেফারেন্স গণনাটি 1 এর সমান হয়ে গেলে পিছনে এবং ফ্রি হয়ে যান, যদি এটি বেশি হয় তবে আপনি কেবল একটি সরিয়ে ফেলুন।

Atomic Cycle A

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

যেমনটি আপনি আগে দেখেছেন, পারমাণবিক পথের সন্ধানের সময় পুরো গ্রাফটি ট্রান্সভার করা হচ্ছে। পরিবর্তে, আমরা অনুসন্ধানের অঞ্চলটি এ.র সাথে দৃ connected়ভাবে সংযুক্ত উপাদানগুলিতে সীমাবদ্ধ করতে পারি এই উপাদানগুলি সন্ধানের জন্য টার্জনের অ্যালগোরিদম সহ গ্রাফের একটি সরল পথ প্রয়োজন।

পারমাণবিক পথ এবং চক্রের সংমিশ্রণ

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


এটি জিজ্ঞাসা করা প্রশ্নের উত্তর বলে মনে হচ্ছে না।
ইলমারি করোনেন

0

অন্য কয়েকটি পোস্টারের দ্বারা সংক্ষিপ্ত বিবরণ হিসাবে, সংক্ষেপে সমস্যাটি হল যোগাযোগের শেষ নোডগুলির মধ্যে সমস্ত পাথের সংমিশ্রনের জন্য গ্রাফটি পুনরাবৃত্তভাবে অনুসন্ধান করতে গভীরতার প্রথম অনুসন্ধান অ্যালগরিদম ব্যবহার করা।

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

অনুসন্ধানটি ব্যাকট্র্যাকগুলি সর্বাধিক সাম্প্রতিক নোডে ফিরে আসে এটি এখনও অনুসন্ধান শেষ করে নি finished

আমি খুব সম্প্রতি এই বিষয়টি সম্পর্কে ব্লগ করেছি , প্রক্রিয়াটিতে সি ++ বাস্তবায়নের একটি উদাহরণ পোস্ট করছি।


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();  
                }
            }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.