📜  克隆有向无环图

📅  最后修改于: 2022-05-13 01:57:54.290000             🧑  作者: Mango

克隆有向无环图

有向无环图 (DAG) 是不包含循环且具有有向边的图。我们得到一个 DAG,我们需要克隆它,即创建另一个图,该图具有其顶点和连接它们的边的副本。

例子:

Input :
 
0 - - - > 1 - - - -> 4
|        /  \        ^   
|       /    \       |  
|      /      \      |
|     /        \     |  
|    /          \    |
|   /            \   |
v  v              v  |
2 - - - - - - - - -> 3


Output : Printing the output of the cloned graph gives: 
0-1
1-2
2-3
3-4
1-3
1-4
0-2

克隆 DAG 而不将图形本身存储在哈希(或Python中的字典)中。为了克隆,我们基本上对节点进行深度优先遍历,获取原始节点的值并使用相同的值初始化新的相邻节点,递归执行,直到完全遍历原始图。下面是克隆 DAG 的递归方法(在Python中)。我们在Python中使用动态列表,对这个列表进行追加操作是在恒定时间内发生的,因此可以快速有效地初始化图。

C++14
// C++ program to clone a directed acyclic graph.
#include 
using namespace std;
 
// Class to create a new graph node
class Node
{
    public:
        int key;
        vector adj;
         
        // key is the value of the node
        // adj will be holding a dynamic
        // list of all Node type neighboring
        // nodes
        Node(int key)
        {
            this->key = key;
        }
};
 
// Function to print a graph,
// depth-wise, recursively
void printGraph(Node *startNode,
                vector &visited)
{
     
    // Visit only those nodes who have any
    // neighboring nodes to be traversed
    if (!startNode->adj.empty())
    {
         
        // Loop through the neighboring nodes
        // of this node. If source node not already
        // visited, print edge from source to
        // neighboring nodes. After visiting all
        // neighbors of source node, mark its visited
        // flag to true
        for(auto i : startNode->adj)
        {
            if (!visited[startNode->key])
            {
                cout << "edge " << startNode
                     << "-" << i
                     << ":" << startNode->key
                     << "-" << i->key
                     << endl;
                if (!visited[i->key])
                {
                    printGraph(i, visited);
                    visited[i->key] = true;
                }
            }
        }
    }
}
 
// Function to clone a graph. To do this, we
// start reading the original graph depth-wise,
// recursively. If we encounter an unvisited
// node in original graph, we initialize a
// new instance of Node for cloned graph with
// key of original node
Node *cloneGraph(Node *oldSource,
                 Node *newSource,
                 vector &visited)
{
    Node *clone = NULL;
     
    if (!visited[oldSource->key] &&
        !oldSource->adj.empty())
    {
        for(auto old : oldSource->adj)
        {
             
            // Below check is for backtracking, so new
            // nodes don't get initialized everytime
            if (clone == NULL ||
               (clone != NULL &&
               clone->key != old->key))
                clone = new Node(old->key);
                 
            newSource->adj.push_back(clone);
            cloneGraph(old, clone, visited);
             
            // Once, all neighbors for that particular node
            // are created in cloned graph, code backtracks
            // and exits from that node, mark the node as
            // visited in original graph, and traverse the
            // next unvisited
            visited[old->key] = true;
        }
    }
    return newSource;
}
 
// Driver Code
int main()
{
    Node *n0 = new Node(0);
    Node *n1 = new Node(1);
    Node *n2 = new Node(2);
    Node *n3 = new Node(3);
    Node *n4 = new Node(4);
     
    n0->adj.push_back(n1);
    n0->adj.push_back(n2);
    n1->adj.push_back(n2);
    n1->adj.push_back(n3);
    n1->adj.push_back(n4);
    n2->adj.push_back(n3);
    n3->adj.push_back(n4);
     
    // Flag to check if a node is already visited.
    // Stops indefinite looping during recursion
    vector visited(5, false);
    cout << "Graph Before Cloning:-\n";
    printGraph(n0, visited);
    visited = { false, false, false, false, false };
     
    cout << "\nGraph Before Starts:-\n";
    Node *clonedGraphHead = cloneGraph(
        n0, new Node(n0->key), visited);
    cout << "Cloning Process Completes.\n";
     
    visited = { false, false, false, false, false };
    cout << "\nGraph After Cloning:-\n";
    printGraph(clonedGraphHead, visited);
     
    return 0;
}
 
// This code is contributed by sanjeev2552


Java
// Java program to clone a directed acyclic graph.
import java.util.*;
 
class GFG{
 
// Class to create a new graph node
static class Node
{
    int key;
    ArrayList adj = new ArrayList();
     
    // key is the value of the node
    // adj will be holding a dynamic
    // list of all Node type neighboring
    // nodes
    Node(int key)
    {
        this.key = key;
    }
}
 
// Function to print a graph,
// depth-wise, recursively
static void printGraph(Node startNode,
                       boolean[] visited)
{
     
    // Visit only those nodes who have any
    // neighboring nodes to be traversed
    if (!startNode.adj.isEmpty())
    {
         
        // Loop through the neighboring nodes
        // of this node. If source node not already
        // visited, print edge from source to
        // neighboring nodes. After visiting all
        // neighbors of source node, mark its visited
        // flag to true
        for(Node i : startNode.adj)
        {
            if (!visited[startNode.key])
            {
                System.out.println("edge " + startNode +
                             "-" + i + ":" + startNode.key +
                             "-" + i.key);
                 
                if (!visited[i.key])
                {
                    printGraph(i, visited);
                    visited[i.key] = true;
                }
            }
        }
    }
}
 
// Function to clone a graph. To do this, we
// start reading the original graph depth-wise,
// recursively. If we encounter an unvisited
// node in original graph, we initialize a
// new instance of Node for cloned graph with
// key of original node
static Node cloneGraph(Node oldSource,
                       Node newSource,
                       boolean[] visited)
{
    Node clone = null;
     
    if (!visited[oldSource.key] &&
        !oldSource.adj.isEmpty())
    {
        for(Node old : oldSource.adj)
        {
             
            // Below check is for backtracking, so new
            // nodes don't get initialized everytime
            if (clone == null ||
               (clone != null &&
                clone.key != old.key))
                clone = new Node(old.key);
                 
            newSource.adj.add(clone);
            cloneGraph(old, clone, visited);
             
            // Once, all neighbors for that particular node
            // are created in cloned graph, code backtracks
            // and exits from that node, mark the node as
            // visited in original graph, and traverse the
            // next unvisited
            visited[old.key] = true;
        }
    }
    return newSource;
}
 
// Driver Code
public static void main(String[] args)
{
    Node n0 = new Node(0);
    Node n1 = new Node(1);
    Node n2 = new Node(2);
    Node n3 = new Node(3);
    Node n4 = new Node(4);
     
    n0.adj.add(n1);
    n0.adj.add(n2);
    n1.adj.add(n2);
    n1.adj.add(n3);
    n1.adj.add(n4);
    n2.adj.add(n3);
    n3.adj.add(n4);
     
    // Flag to check if a node is already visited.
    // Stops indefinite looping during recursion
    boolean visited[] = new boolean[5];
    System.out.println("Graph Before Cloning:-");
    printGraph(n0, visited);
    Arrays.fill(visited, false);
     
    System.out.println("\nCloning Process Starts");
    Node clonedGraphHead = cloneGraph(
        n0, new Node(n0.key), visited);
    System.out.println("Cloning Process Completes.");
     
    Arrays.fill(visited, false);
    System.out.println("\nGraph After Cloning:-");
    printGraph(clonedGraphHead, visited);
}
}
 
// This code is contributed by adityapande88


Python3
# Python program to clone a directed acyclic graph.
 
# Class to create a new graph node
class Node():
 
    # key is the value of the node
    # adj will be holding a dynamic
    # list of all Node type neighboring
    # nodes
    def __init__(self, key = None, adj = None):
        self.key = key
        self.adj = adj
 
# Function to print a graph, depth-wise, recursively
def printGraph(startNode, visited):
 
    # Visit only those nodes who have any
    # neighboring nodes to be traversed
    if startNode.adj is not None:
 
        # Loop through the neighboring nodes
        # of this node. If source node not already
        # visited, print edge from source to
        # neighboring nodes. After visiting all
        # neighbors of source node, mark its visited
        # flag to true
        for i in startNode.adj:
            if visited[startNode.key] == False :
                print("edge %s-%s:%s-%s"%(hex(id(startNode)), hex(id(i)), startNode.key, i.key))
                if visited[i.key] == False:
                    printGraph(i, visited)
                    visited[i.key] = True
 
# Function to clone a graph. To do this, we start
# reading the original graph depth-wise, recursively
# If we encounter an unvisited node in original graph,
# we initialize a new instance of Node for
# cloned graph with key of original node
def cloneGraph(oldSource, newSource, visited):
    clone = None
    if visited[oldSource.key] is False and oldSource.adj is not None:
        for old in oldSource.adj:
 
            # Below check is for backtracking, so new
            # nodes don't get initialized everytime
            if clone is None or(clone is not None and clone.key != old.key):
                clone = Node(old.key, [])
            newSource.adj.append(clone)
            cloneGraph(old, clone, visited)
 
            # Once, all neighbors for that particular node
            # are created in cloned graph, code backtracks
            # and exits from that node, mark the node as
            # visited in original graph, and traverse the
            # next unvisited
            visited[old.key] = True
    return newSource
 
# Creating DAG to be cloned
# In Python, we can do as many assignments of
# variables in one single line by using commas
n0, n1, n2 = Node(0, []), Node(1, []), Node(2, [])
n3, n4 = Node(3, []), Node(4)
n0.adj.append(n1)
n0.adj.append(n2)
n1.adj.append(n2)
n1.adj.append(n3)
n1.adj.append(n4)
n2.adj.append(n3)
n3.adj.append(n4)
 
# flag to check if a node is already visited.
# Stops indefinite looping during recursion
visited = [False]* (5)
print("Graph Before Cloning:-")
printGraph(n0, visited)
 
visited = [False]* (5)
print("\nCloning Process Starts")
clonedGraphHead = cloneGraph(n0, Node(n0.key, []), visited)
print("Cloning Process Completes.")
 
visited = [False]*(5)
print("\nGraph After Cloning:-")
printGraph(clonedGraphHead, visited)


输出:

Graph Before Cloning:-
edge 0x7fa03dd43878-0x7fa03dd43908:0-1
edge 0x7fa03dd43908-0x7fa03dd43950:1-2
edge 0x7fa03dd43950-0x7fa03dd43998:2-3
edge 0x7fa03dd43998-0x7fa03dd439e0:3-4
edge 0x7fa03dd43908-0x7fa03dd43998:1-3
edge 0x7fa03dd43908-0x7fa03dd439e0:1-4
edge 0x7fa03dd43878-0x7fa03dd43950:0-2

Cloning Process Starts
Cloning Process Completes.

Graph After Cloning:-
edge 0x7fa03dd43a28-0x7fa03dd43a70:0-1
edge 0x7fa03dd43a70-0x7fa03dd43ab8:1-2
edge 0x7fa03dd43ab8-0x7fa03dd43b00:2-3
edge 0x7fa03dd43b00-0x7fa03dd43b48:3-4
edge 0x7fa03dd43a70-0x7fa03dd43b90:1-3
edge 0x7fa03dd43a70-0x7fa03dd43bd8:1-4
edge 0x7fa03dd43a28-0x7fa03dd43c20:0-2

通过将相邻边附加到顶点来创建 DAG 发生在 O(1) 时间内。图的克隆需要 O(E+V) 时间。

推荐帖子: