Search code examples
c++functionrecursionadjacency-matrixundirected-graph

Counting nodes in the largest cycle of an adjacency matrix


I am currently writing a program using an undirected graph. Im representing this by creating an adjacency matrix of the connections.

if(adjacency_matrix[i][j] == 1){
    //i and j have and edge between them
}
else{
    //i and j are not connected
}

What I am attempting to do is to find all the nodes that a given node is connected to (by any series of edges). I have tried to write a function that does this for a given node and returns a vector that contains either a 1 or 0 in each spot in the vector determined by whether the node is reachable by the given node by any path in the graph. I then want to take this vector and add up all the values in it, which will return the amount of nodes reachable by that node. I want to then take all these values for every node in the graph and put them in a vector, and then find the max value, which would represent the amount of nodes in the largest cycle.

My issue is not that Im receiving errors with my function definition code (although I am), but rather that I realize I am writing this recursive function incorrectly, but am without a clue as to how to alter it to satisfy my need. I have included my code below, any guidance would be much appreciated.

Function definition:

vector<int> get_conn_vect(int u, int conns, vector<vector<int>> vv, vector<int> seen)
{
    seen.at(u) = 1;
    while(v < conns)
    {
        if(seen.at(v) == 0 && vv.at(u).at(v) == 1)
        {
            get_conn_vect(v, conns, vv, seen);
            v++;
        }

        else
        {
            v++;
        }
    }
    return seen;
}

Call in main.cpp:

std::vector<int> conn_vect;
int sum_of_elems = 0;
for(int i = 0; i < num_nodes; i++)
{
    std::vector<int> seen_vect(matrix.size());
    sum_of_elems = 0;
    seen_vect = get_conn_vect(i, num_conn, matrix, seen_vect);
    conn_vect.push_back(sum_of_elems = std::accumulate(seen_vect.begin(), seen_vect.end(), 0));
}

Solution

  • As Linxi's comment says, you are copying the seen vector on every invocation of your recursive function so that the value returned back to your main function has exactly one nonzero entry at index i. Pass a reference instead (I've also passed the matrix as reference to const to prevent unnecessary copies):

    void get_conn_vect(int u, const vector< vector<int> > &vv, vector<int> &seen)
    {
        seen.at(u) = 1;
    
        // Assuming that vv is square.
        for(int v = 0; v < vv.size(); ++v)
        {
            if(seen.at(v) == 0 && vv.at(u).at(v) == 1)
            {
                get_conn_vect(v, conns, vv, seen);
            }
        }
    }
    

    At the end of the recursion the vector you initially passed contains a nonzero entry for each node that is connected to node i.


    Another very neat solution using a different approach appears once one realizes that the entries (i,j) of a power A^n of the adjacency matrix A describe the number of paths to get from node i to node j in exactly n steps. Hence one can calculate the connectivity sets of all nodes simultaneously by simply adding up powers of the adjacency matrix B = A + A^2 + ... + A^N, where N is the number of nodes (no path between distinct nodes can be longer than that). To get the number of nodes connected to node i simply count the number of nonzeros in the i'th column (or row) of B.