图论 - 循环长度无向图 - 邻接矩阵

时间:2015-05-06 01:16:52

标签: algorithm graph graph-algorithm

算法部分综合考试的研究复习题。

  

设G是一个无向图,其中n个顶点恰好包含一个周期和孤立顶点(即没有叶子)。这意味着如果顶点不在循环中,则顶点的程度为0(隔离),如果它是循环的一部分,则为2。假设图表由邻接矩阵重新表示。 描述一个找到周期长度的效果算法。

我正在寻求帮助来验证我的理解,检查它是否正确以及分析是否正确。

我的答案(伪pythonic)

visited = [] // this will be list of u,v pairs belonging to cycle

for each u,v in G[][]:
    if G[u][v] == 1:      // is an edge
        if G[u][v] in visited : // 
            return len(visited) // return the length of the cycle, since weve hit begining of cycle
        else :
             visited.add((u,v))

基于英语的理解

  • 我们知道必须存在一个周期,问题的定义,不需要考虑周期的情况

  • 对于每对顶点,检查它是否为边

  • 如果是边缘,请检查我们之前是否曾经在那里。如果有,我们找到了循环,并返回所有访问边的大小。 (周期大小)

  • 如果它不是访问边缘,请将其添加到访问列表,并继续直到找到源边缘(将循环增加1直到我们到达源)

我认为我的分析可能会失败。因为我们至少访问每个(u,v)对,然后检查它是否是边缘,以及每边缘2次比较。我认为它涉及O(| v | ^ 2 + 2 | E |)

  • 顶点数,平方(因为我们访问矩阵中的每一对),每边+ 2次比较。

有人可以就效率和正确性提出建议吗?如果我可能有一个逻辑上的飞跃,也可能提供更多基于英语的理解,而不承认逻辑证明?

感谢您的阅读并提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

考虑到问题中的条件(即图中唯一的边是周期的一部分),周期的长度是图中的边数,这是邻接矩阵中1的数量的一半。 (每个边(i,j)在邻接矩阵中出现两次:A [i,j] = 1且A [j,i] = 1)。

因此,明显的算法是将邻接矩阵的条目求和并除以2.如果有V个顶点,则为O(V ^ 2)。

看起来可能会有所帮助的一件事是,一旦你在邻接矩阵中找到第一个1,就要跟随边缘,直到你回到起点:

Find i, j such that A[i, j]=1.
start = i
cycle_length = 1
repeat
    find k != i with A[j, k] = 1
    i, j = j, k
    cycle_length++
until i = start

此过程终止后,cycle_length是周期的长度。尽管如此,这仍然是最坏情况的O(V ^ 2),尽管如果你能在周期中快速找到一个顶点,它就是O(V * C),其中C是周期的长度。

您问题中的代码无效。您将(u,v)作为矩阵中的索引进行迭代,并且无法找到相同的(u,v)两次。

答案 1 :(得分:1)

由于只有一个周期,如果一个顶点连接到至少另一个顶点,则顶点是周期的一部分。由于图表是无向的,因此可以使用以下规则: if a edge between v1 and v2 exists, the edge aswell exists between v2 and v1或换句话说:算法只需要扫描给出v1 < v2的矩阵部分,这样即使在最坏情况下读取的矩阵元素数量也会减少50%以上。而且由于正在搜索一个循环,我们可以简单地保存我们在前一个节点之前访问过的每个节点,以确保我们不再访问它并结束,如果我们最终当前节点等于起始节点。 / p>

//search for any node that is in the cycle
int firstNode = -1

for int i in 1 , len(graph)
    boolean notIsolated = false

    for int j in 0 , i - 1
         if graph[i][j] == 1
             notIsolated = true
             break

    if notIsolated
         firstNode = i
         break

int node_c = firstNode
int node_p = -1
int count = 0

do
    //search the neighbour that isn't the previous node with above given
    //optimizations
    int n
    for n in 0 , node_c - 1
        if graph[node_c][n] == 1 AND n != node_p
             break

    //update the nodevars for the next step
    node_p = node_c
    node_c = n        

    ++count
while node_c != firstNode //continue until the algorithm reaches the startnode

除此之外,还有很多优点(至少我不知道如何进一步优化运行时)。