【问题标题】:How to generate and plot all spanning trees?如何生成和绘制所有生成树?
【发布时间】:2021-12-16 00:59:03
【问题描述】:

我有一个玩具图g,然后我找到了the number of spanning trees by cofactor of the Laplacian。数字是 11。

library(igraph)
set.seed(2)
n <- 5   #  n=5
m <- 6   #  m=6
g <- erdos.renyi.game(n, p.or.m=m, type="gnm" , directed=FALSE, loops=FALSE)

lap_mat <- laplacian_matrix(g)   
print(paste("number of spanning trees by cofactor = ", det(lap_mat[-1,-1])))
# 11

我有n=5 顶点,我绘制了原始图:

par(mfrow=c(2, 3))
layout <- layout.fruchterman.reingold(g)
plot(g, main="Original graph", vertex.size = 40, layout = layout)

然后使用graph.bfs() function 创建了 5 个生成树:

for (i in 1:n) {
  r <- graph.bfs(g, root=i, order=TRUE, father=TRUE)
  h <- graph(rbind(r$order, r$father[r$order, na_ok = TRUE])[, -1], directed=FALSE)
  plot(h, main=paste("Spanning tree for root=", i), vertex.size = 40, layout = layout)
}

我需要绘制所有生成树。例如,不创建根 = 5 的下一棵树:

问题。为小型随机图生成所有树的可能方法是什么?

【问题讨论】:

  • 你从哪里得到 11 棵树?你从 1 循环到 n = 5 所以最终有 5 棵树。您有 5 个顶点,拉普拉斯算子的维度为 5 x 5,并且有 5 个根开始用于广度优先搜索。
  • @MauritsEvers,为了找到给定图中的生成树总数,我计算了拉普拉斯矩阵 'det(lap_mat[-1,-1) 中 (1,1) 元素的辅因子])'。这个数字相当于图中生成树的总数。
  • 你遍历所有顶点for (i in 1:n)。由于n=5(根据您的设计),您最终会得到 5 个图表。不知道你期望这会如何产生 11 个图表。也许这是一个 XY 问题?
  • @Szabolcs 是的,现在问题更清楚了。最初,OP 的困惑在于如何计算所有生成树(ST)并不明显。关于生成 ST 的算法的评论是 Algorithms for generating all possible spanning trees of a simple undirected connected graph: an extensive review。许多方法使用 BFS 来生成 initial ST;然后可以从这个初始 ST 生成所有其他 ST。我建议看一下评论。在 R 中实现这些方法之一应该不会(太)困难。
  • 我打开了一个功能请求:github.com/igraph/igraph/issues/1827@Nick 如果您可以评论您的动机,这将有助于确定问题的优先级。

标签: r algorithm graph-theory igraph spanning-tree


【解决方案1】:

首先,我想说,我下面的解决方案是一种蛮力方法,因此只适用于小尺寸的图,即没有很多顶点或弧。

如果你有大型网络,你应该参考一些更高级的算法,例如,https://link.springer.com/article/10.1007/s40747-018-0079-7


由于您有 6 个弧和 5 个顶点,因此您只需从 6 个弧中删除 2 个即可找到生成树。会有combn(6,2)选项,你可以将这些边组合一一删除,看看是否还有生成树

Filter(
  function(x) length(decompose(x)) == 1,
  combn(
    ecount(g),
    ecount(g) - vcount(g) + 1,
    FUN = function(x) delete.edges(g, E(g)[x]),
    simplify = FALSE
  )
)

给出所有 11 棵生成树

[[1]]
IGRAPH 9692f3d U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 9692f3d:
[1] 2--4 3--4 1--5 2--5

[[2]]
IGRAPH 969368e U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 969368e:
[1] 1--3 3--4 1--5 2--5

[[3]]
IGRAPH 969368e U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 969368e:
[1] 1--3 2--4 1--5 2--5

[[4]]
IGRAPH 96938fa U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 96938fa:
[1] 1--3 2--4 3--4 2--5

[[5]]
IGRAPH 96938fa U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 96938fa:
[1] 1--3 2--4 3--4 1--5

[[6]]
IGRAPH 9693ded U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 9693ded:
[1] 1--2 2--4 3--4 2--5

[[7]]
IGRAPH 969404b U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 969404b:
[1] 1--2 2--4 3--4 1--5

[[8]]
IGRAPH 96942b7 U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 96942b7:
[1] 1--2 1--3 3--4 2--5

[[9]]
IGRAPH 9694527 U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 9694527:
[1] 1--2 1--3 3--4 1--5

[[10]]
IGRAPH 9694527 U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 9694527:
[1] 1--2 1--3 2--4 2--5

[[11]]
IGRAPH 9694797 U--- 5 4 -- Erdos renyi (gnm) graph
+ attr: name (g/c), type (g/c), loops (g/l), m (g/n)
+ edges from 9694797:
[1] 1--2 1--3 2--4 1--5

【讨论】:

    【解决方案2】:

    首先让我们注意以下几点:

    1. 对于原始图 G,我们有 |V(G)| = 5, |E(G)| = 6

    2. 图 G 的生成树 T 恰好有 V(G)-1=4 个顶点。

    3. 但这并不意味着我们可以从 G 中任意选择并删除任意 2 条边,从而得到生成树 T。例如,如果我们选择删除边 (1,5) 和 (2,5),我们应获得以下不连通图,它不是树:

    4. 让我们在图中找到从顶点 1 开始的循环。请注意,由于从顶点 1 到 2 有一条边,因此找到从 1 开始到顶点 2 结束的所有可能的路径(长度 >1)。现在,如果我们通过在最后添加边 (2,1) 来扩展每条路径,我们将在简单图 G 中找到所有可能的循环,从顶点 1 开始/结束,就像在下一个代码块中所做的那样:

      cycle_edges <- c()
      C <- list() # all possible cycles staring / ending on vertex 1
      for (path in all_simple_paths(g, 1, 2, mode="out")) {
         pn <- length(path)
         if (pn > 2) { # not a single edge
            cycle <- c(as.vector(path), 1)
            name <- paste(cycle, collapse='')
            C[[name]] <- c()
            for (i in 1:pn) {
               C[[name]] <- c(C[[name]], paste(cycle[i], cycle[i+1], sep='|'))    
            }
         } 
      }
      

      图中的两个循环如下所示:

      C
      # $`13421`
      # [1] "1|3" "3|4" "4|2" "2|1"    
      # $`1521`
      # [1] "1|5" "5|2" "2|1"
      
    5. 现在从每个循环中选择一条边来删除并生成唯一的生成树:

      par(mfrow=c(4,3))
      count <- 1
      for (e1 in C[[1]]) {
         for (e2 in C[[2]]) {
            if (e1 != e2) { # make sure not to remove same edge twice
               g1 <- g %>% delete_edges(c(e1, e2))
               plot(g1, main=paste("spanning tree", count), layout = layout)
               count <- count + 1
             }
          }
       }
      

    【讨论】:

    • 你的解决方案很有趣,但是可以分享一下你的解决方案吗?例如,当三角形 1-2-5 不存在时。
    • @Nick 如果图中有多个循环,我们通常需要从每个循环中删除一条边以生成生成树。如果我们有 n 个具有 m_1、m_2、...、m_n 边的不相交循环,则将有 m_1.m_2...m_n 种方法来删除边,从而产生那么多生成树。如果循环共享边,我们需要分别处理这些边。例如,给定的图包含 2 个具有 3 条边和 4 条边的循环,它们之间有一条公共边 (1,2),这意味着我们将有 3*4-1=11 棵生成树。
    • 如果图有一个单环,其中有 m 个节点,我们可以正好有 m 个生成树,因为有 m 种方法可以从环中删除一条边并使图无环。跨度>
    • 当三角形 1-2-5 不存在时,图只包含一个长度为 4 的循环,因此可以通过 4 种方法从循环中删除一条边以创建 4 棵生成树。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多