简体   繁体   中英

Maximum Simple Cycle in Directed Graph

Maximum Simple Cycle (product) in a graph

Hello,

I have constructed a directed graph G=(v,e) and I would like to find the maximum simple cycle in this graph, where edge weights are multiplied instead of added. My initial method for doing so is to construct a new graph, G=(v,e'), where e'(i,j) = 1/e(i,j)/min(e'), and then to apply Floyd-Warshall on this graph to find all shortest paths. My thoughts were that after inverting the graph, the maximum path would then become the minimum, and if we divide by the minimum value, all edge weights will be "positive" (>= 1, since we are multiplying instead of adding). However, when I run the algorithm (my Python code is below) it seems to not work, and I'm wondering if it's because my algorithm won't work at all or if it's because of an error in my code.

#construct G' = (V,dist) for our modified Floyd-Warshall algorithm
# edge weights are initially the inverse of w(u,v). They are then all divided
# by the minimum value to ensure all are >= 1
dist = {}
nxt = {}
minimum = float("inf")
for i in e:
    dist[i] = {}
    nxt[i] = {}
    for j in e[i]:
        dist[i][j] = 1/e[i][j]
        nxt[i][j] = j
        if dist[i][j] < minimum:
            minimum = dist[i][j]

for i in dist:
    for j in dist[i]:
        dist[i][j] /= minimum

# Perform Floyd-Warshall
for k in v:
    for i in v:
        for j in v:
            try:
                one = dist[i][j]
                two = dist[i][k]
                three = dist[k][j]
            except KeyError:
                continue

            if one > two * three:
                dist[i][j] = two * three
                nxt[i][j] = nxt[i][k]

# Find the shortest cycle using shortest paths
minimum = float("inf")
for i in v:
    for j in v:
        if i == j:
            continue
        try:
            one = dist[i][j]
            two = dist[j][i]
        except KeyError:
            continue

        if one * two < minimum:
            minimum = one * two
            pair = [i,j]

def Path(u,v):
    if nxt[u][v] == None:
        return []
    path = [u]
    while u != v:
        u = nxt[u][v]
        path.append(u)
    return path

# Format the cycle for output
p1 = Path(pair[0],pair[1])
p2 = Path(pair[1],pair[0])
p = p1 + p2[1:]
print(p)

# Find the total value of the cycle
value = 1
for i in range(len(p)-1):
    value *= e[p[i]][p[i+1]]

print('The above cycle has a %f%% weight.'  % ((value-1)*100))

I tested the above example with a graph G=(V,E), where

V = {a,b,c,d}, and 
E = {
    (a,b): 1/0.00005718 * 0.9975, 
    (a,c): 1/0.03708270 * 0.9975,
    (a,d): 18590.00000016 * 0.9975, 
    (b,a): 0.00010711 * 0.9975,
    (b,c): 0.00386491 * 0.9975, 
    (c,a): 0.03700994 * 0.9975,
    (c,b): 1/18590.00000017 * 0.9975,
    (c,d): 688.30000000 * 0.9975,
    (d,a): 1/18590.00000017 * 0.9975,
    (d,c): 1/688.30000000 * 0.9975
}

The output with the above graph is that the cycle [a,d,a] is the best, with a 86.385309% weight. However, as we can see, the cycle [a,b,c,a] has a 148.286055% weight, which is much better, which leads me to believe that either my algorithm is wrong or I have an error somewhere.

Any advice is much appreciated!!

I think that the problem is not the implementation but the algorithm. Indeed take the following exemple with four vertices a, b, c and d, and the following edges:

w(a,b)=10/3

w(b,c)=10

w(c,d)=5

w(d,a)=10/3

w(d,b)=5

Then, your algorithm will return directed cycle (b,c,d,b) whereas the optimal solution is (a,b,c,d,a).

Moreover, you should also know that your problem is probably NP-complete, since the Longest Path problem is NP-complete (even if the Shortest Path problem is polynomially solvable), so there is only a few hopes that there is a so simple algorithm for your problem.

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