Search code examples
pythonalgorithmgraphpath-finding

Find all paths of length 2 in a graph


I've tried to create an algorithm for finding all paths of length 2, but it doesn't seem to work properly:

input_split = input().split(' ')
node_count = int(input_split[0])
input_count = int(input_split[1])
items = np.zeros((node_count, node_count), dtype=np.int32) # matrix of adjacency
for j in range(input_count):
    split = input().split(' ')
    x = int(split[0]) - 1 # convert 1 based coordinates to 0 based
    y = int(split[1]) - 1
    items[x][y] = 1
    items[y][x] = 1
result = np.linalg.matrix_power(items, 2)
result_sum = int(np.sum(result) / 2) # reverse paths are counted only once
print(result_sum)

Sample input:

6 7
1 2
2 3
3 1
2 4
4 5
5 6
6 2

The result should be 11, but it prints 18.


Solution

  • You're on the right track when calculating the square of the adjacency matrix. After the exponentiation you would get result matrix that looks like this:

    [[2 1 1 1 0 1]
     [1 4 1 0 2 0]
     [1 1 2 1 0 1]
     [1 0 1 2 0 2]
     [0 2 0 0 2 0]
     [1 0 1 2 0 2]]
    

    First you need to exclude all diagonal entries from this matrix, because those denote walks that are not paths, as their starting and ending node is the same. Note that for length 2 that is the only way how nodes can be repeating.

    The other entries need to be counted only once, because of symmetry. So only look at the upper right triangle of the matrix.

    One way to do it is:

    result_sum = 0
    for i in range(input_count - 1):
        for j in range(i + 1, input_count - 1):
            result_sum += result[i][j]
    print(result_sum) # prints 11
    

    More Pythonic way, one-liner using numpy.trace():

    result_sum = (np.sum(result) - np.trace(result)) // 2