简体   繁体   中英

All simple paths of an undirected, strongly connected graph

I have been trying to learn more about graph traversal in my spare time, and I am trying to use depth-first-search to find all simple paths between a start node and an end node in an undirected, strongly connected graph. So far I have been using this code from Print all paths from a given source to a destination , which is only for a directed graph.

The main algorithm, using recursive DFS, occurs in these two functions:

void Graph::printAllPaths(int s, int d)
{
    // Mark all the vertices as not visited
    bool *visited = new bool[V];

    // Create an array to store paths
    int *path = new int[V];
    int path_index = 0; // Initialize path[] as empty

    // Initialize all vertices as not visited
    for (int i = 0; i < V; i++)
        visited[i] = false;

    // Call the recursive helper function to print all paths
    printAllPathsUtil(s, d, visited, path, path_index);
}

// A recursive function to print all paths from 'u' to 'd'.
// visited[] keeps track of vertices in current path.
// path[] stores actual vertices and path_index is current
// index in path[]
void Graph::printAllPathsUtil(int u, int d, bool visited[],
                          int path[], int &path_index)
{
    // Mark the current node and store it in path[]
    visited[u] = true;
    path[path_index] = u;
    path_index++;

    // If current vertex is same as destination, then print
    // current path[]
    if (u == d)
    {
        for (int i = 0; i<path_index; i++)
            cout << path[i] << " ";
        cout << endl;
    }
    else // If current vertex is not destination
    {
        // Recur for all the vertices adjacent to current vertex
        list<int>::iterator i;
        for (i = adj[u].begin(); i != adj[u].end(); ++i)
            if (!visited[*i])
                printAllPathsUtil(*i, d, visited, path, path_index);
    }

    // Remove current vertex from path[] and mark it as unvisited
    path_index--;
    visited[u] = false;
}

Which works fine for a directed graph, but not a undirected, strongly connected graph.

I was wondering if their is a way to tweak this code to also work for an undirected graph? I have a feeling more backtracking is needed to explore more possible paths, but am unsure as to how to approach this.

Any help would be appreciated.

RoadRunner, are you sure that you "undirected issue" is in the code you show? It looks OK at the first glance. Maybe the bug is comming from the fact you didn't fix addEdge to make graph you create undirected such as:

void Graph::addEdge(int u, int v)
{
    adj[u].push_back(v); 
    adj[v].push_back(u); // Fix: add back edge as well!
}

Update (C code, but very ugly)

OK, here is my attempt to translate code to pure C. Obviously code style is ugly and there are no error checks at all but you can improve that as I expect you to be much more proficient in C. Also I just rolled out my simple custom linked-list of graph nodes with a bit strange name NodeListNode ie ListNode containing a graph Node.

Graph.h

#pragma once

#ifdef __cplusplus
extern "C" {  // only need to export C interface if
              // used by C++ source code
#endif

    typedef struct tagNodeListNode {
        struct tagNodeListNode* next;
        int index;
    } NodeListNode;

    typedef struct tagGraph {
        int nodesCount;
        NodeListNode** adjArr;
    } Graph;


    typedef void(*GraphPathVisitorFunc)(NodeListNode const* const path);

    Graph GraphCreate(int nodesCount);
    void GraphDestroy(Graph gr);
    void GraphAddEdge(Graph gr, int u, int v);
    void GraphVisitAllPaths(Graph gr, int s, int d, GraphPathVisitorFunc visitor);
    void GraphPrintAllPaths(Graph gr, int s, int d);


#ifdef __cplusplus
}
#endif

Graph.c

#include "Graph.h"

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


Graph GraphCreate(int nodesCount)
{
    // calloc ensures zeroing array
    NodeListNode** adjArr = (NodeListNode**)calloc(nodesCount, sizeof(NodeListNode*));
    Graph gr = { nodesCount, adjArr };
    return gr;
}

void GraphDestroy(Graph gr)
{
    for (int i = 0; i < gr.nodesCount; i++)
    {
        for (NodeListNode* adj = gr.adjArr[i]; adj != NULL;)
        {
            NodeListNode* tmp = adj;
            adj = adj->next; //first move on the free
            free(tmp);
        }
    }
    free(gr.adjArr);
}

void GraphAddEdgeImplFirst(Graph gr, int from, int to)
{
    NodeListNode* adj = gr.adjArr[from];
    NodeListNode* n = (NodeListNode*)malloc(sizeof(NodeListNode));
    n->next = adj;
    n->index = to;
    gr.adjArr[from] = n;
}

void GraphAddEdgeImplLast(Graph gr, int from, int to)
{
    NodeListNode* adj = gr.adjArr[from];
    NodeListNode* n = (NodeListNode*)malloc(sizeof(NodeListNode));
    n->next = NULL;
    n->index = to;
    if(adj == NULL)
    {
        gr.adjArr[from] = n;
    }
    else
    {
        while (adj->next != NULL)
            adj = adj->next;
        adj->next = n;
    }
}



void GraphAddEdge(Graph gr, int u, int v)
{
    GraphAddEdgeImplFirst(gr, u, v);
    GraphAddEdgeImplFirst(gr, v, u);

    // closer to https://ideone.com/u3WoIJ but slower and thus makes no sense
    //GraphAddEdgeImplLast(gr, u, v);
    //GraphAddEdgeImplLast(gr, v, u);
}


void GraphVisitAllPathsImpl(Graph gr, int cur, int dst, GraphPathVisitorFunc visitor, NodeListNode* pathFst, NodeListNode* pathLst, bool* visited)
{
    if (cur == dst)
    {
        visitor(pathFst);
        return;
    }

    NodeListNode* adj = gr.adjArr[cur];
    for (NodeListNode const* tmp = adj; tmp != NULL; tmp = tmp->next)
    {
        int next = tmp->index;
        if (visited[next])
            continue;
        visited[next] = true;
        NodeListNode nextNode = { NULL,next };
        pathLst->next = &nextNode;

        GraphVisitAllPathsImpl(gr, next, dst, visitor, pathFst, &nextNode, visited);

        pathLst->next = NULL;
        visited[next] = false;
    }
}

void GraphVisitAllPaths(Graph gr, int start, int dst, GraphPathVisitorFunc visitor)
{
    bool* visited = calloc(gr.nodesCount, sizeof(bool));
    visited[start] = true;
    NodeListNode node = { NULL,start };
    GraphVisitAllPathsImpl(gr, start, dst, visitor, &node, &node, visited);
    free(visited);
}


void PrintPath(NodeListNode const* const path)
{
    for (NodeListNode const* tmp = path; tmp != NULL; tmp = tmp->next)
    {
        printf("%d ", tmp->index);
    }
    printf("\n");
}

void GraphPrintAllPaths(Graph gr, int s, int d)
{
    GraphVisitAllPaths(gr, s, d, PrintPath);
}

And usage example with a graph identical to your ideaone sample. Note that to get matching output you should use GraphAddEdgeImplLast instead of GraphAddEdgeImplFirst otherwise results will be in reversed order.

void testGraph()
{
    Graph gr = GraphCreate(20);

    GraphAddEdge(gr, 0, 1);
    GraphAddEdge(gr, 0, 7);

    GraphAddEdge(gr, 1, 2);
    GraphAddEdge(gr, 1, 6);
    GraphAddEdge(gr, 1, 5);

    GraphAddEdge(gr, 2, 3);
    GraphAddEdge(gr, 2, 5);

    GraphAddEdge(gr, 3, 4);
    GraphAddEdge(gr, 3, 5);

    GraphAddEdge(gr, 4, 5);
    GraphAddEdge(gr, 4, 10);
    GraphAddEdge(gr, 4, 11);

    GraphAddEdge(gr, 5, 6);
    GraphAddEdge(gr, 5, 10);
    GraphAddEdge(gr, 5, 11);

    GraphAddEdge(gr, 6, 7);
    GraphAddEdge(gr, 6, 8);
    GraphAddEdge(gr, 6, 9);
    GraphAddEdge(gr, 6, 10);

    GraphAddEdge(gr, 7, 8);

    GraphAddEdge(gr, 8, 9);
    GraphAddEdge(gr, 8, 13);

    GraphAddEdge(gr, 9, 10);
    GraphAddEdge(gr, 9, 13);
    GraphAddEdge(gr, 9, 12);

    GraphAddEdge(gr, 10, 12);

    GraphAddEdge(gr, 11, 12);

    GraphAddEdge(gr, 12, 13);
    GraphAddEdge(gr, 12, 14);
    GraphAddEdge(gr, 12, 16);

    GraphAddEdge(gr, 13, 14);

    GraphAddEdge(gr, 14, 15);

    GraphAddEdge(gr, 16, 17);

    GraphAddEdge(gr, 15, 17);
    GraphAddEdge(gr, 15, 19);

    GraphAddEdge(gr, 17, 18);
    GraphAddEdge(gr, 17, 19);

    GraphAddEdge(gr, 18, 19);

    GraphPrintAllPaths(gr, 12, 4);

    GraphDestroy(gr);
}

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM