从scala中的列表中删除有向图的重复周期

时间:2018-09-30 09:58:51

标签: scala graph cycle

我收集了下面显示的列表。

List(4, 0, 1, 2, 4)
List(4, 0, 1, 3, 4)
List(4, 0, 2, 3, 4)
List(4, 3, 2, 3, 4)
List(4, 3, 4, 3, 4)
List(0, 1, 2, 4, 0)
List(0, 1, 3, 4, 0)
List(0, 2, 3, 4, 0)
List(1, 2, 4, 0, 1)
List(1, 3, 4, 0, 1)
List(3, 4, 0, 1, 3)
List(3, 4, 0, 2, 3)
List(3, 2, 3, 2, 3)
List(3, 4, 3, 2, 3)
List(3, 2, 3, 4, 3)
List(3, 4, 3, 4, 3)
List(2, 3, 4, 0, 2)
List(2, 4, 0, 1, 2)
List(2, 3, 2, 3, 2)
List(2, 3, 4, 3, 2)

这些列表是有向图中循环长度为4的各个循环。我想从给定列表中过滤出唯一路径的数量,这些列表之间没有任何更小的路径。例如-List(4,0,1,2,4)和List(0,1,2,4,0)形成相同的循环。另一个示例-List(2,3,2,3,2)仅对2和3进行迭代,并且不形成循环长度4。

从这个集合中我们可以说List(0,1,2,4,0)List(0,1,3,4,0)List(0,2,3,4,0)是唯一路径总数为3 List(0,1,2,4,4,0)和List(4,0,1,2,4)是同一周期,因此我们选择其中之一。

我尝试使用过滤器,但找不到任何逻辑来执行此操作。

3 个答案:

答案 0 :(得分:3)

以下应该有效:

val input = List(List(4, 0, 1, 2, 4),List(4, 0, 1, 3, 4) ,List(4, 0, 2, 3, 4) ,List(4, 3, 2, 3, 4) ,List(4, 3, 4, 3, 4) ,
    List(0, 1, 2, 4, 0) ,List(0, 1, 3, 4, 0) ,List(0, 2, 3, 4, 0) ,List(1, 2, 4, 0, 1) ,List(1, 3, 4, 0, 1) ,List(3, 4, 0, 1, 3) ,
    List(3, 4, 0, 2, 3) ,List(3, 2, 3, 2, 3) ,List(3, 4, 3, 2, 3) ,List(3, 2, 3, 4, 3) ,List(3, 4, 3, 4, 3) ,
    List(2, 3, 4, 0, 2) ,List(2, 4, 0, 1, 2) ,List(2, 3, 2, 3, 2), List(2, 3, 4, 3, 2))

  var uniquePaths: mutable.Set[List[Int]] = collection.mutable.Set[List[Int]]()
  var indexes: ListBuffer[Int] = mutable.ListBuffer[Int]()

  input.zipWithIndex.foreach{x =>
    val (list, index) = (x._1, x._2)
      if(list.head==list.last) {
        val list1 = rotateArray(list.tail)
        if (list1.toSet.size == 4) {
          if(!uniquePaths.contains(list1))
            indexes.append(index)
          uniquePaths.add(list1)
        }
      }
  }

  indexes foreach{x => println(input(x))}

  def rotateArray(xs: List[Int]): List[Int] =
    xs.splitAt(xs.indexOf(xs.min)) match {case (x, y) => List(y, x).flatten}

答案 1 :(得分:1)

...手绘红色循环进行救援。

在相同的四个顶点上有两个不同循环 ,这表明排序不足

enter image description here

该草图假定所有点都是完全连接的图的顶点(省略了边),并且假定循环[0, 1, 2, 3, 0][0, 2, 1, 3, 0]不相同,尽管事实是如果对集合进行排序,则在两种情况下都将获得[0, 1, 2, 3]

以下是替代方法:

  1. 通过过滤掉所有不包含四个不同元素的路径,将不止一次通过同一顶点的所有路径丢弃。
  2. 旋转,将路径表示形式转换为规范形式(例如,从具有最小位置的顶点开始)。
  3. 计算一组规范表示,仅保留唯一路径。

这是实现的样子:

def canonicalize(cycle: List[Int]) = {
  val t = cycle.tail
  val (b, a) = t.splitAt(t.zipWithIndex.minBy(_._1)._2)
  val ab = (a ++ b)
  ab :+ (ab.head)
}

val cycles = List(
  List(4, 0, 1, 2, 4),
  List(4, 0, 1, 3, 4),
  List(4, 0, 2, 3, 4),
  List(4, 3, 2, 3, 4),
  List(4, 3, 4, 3, 4),
  List(0, 1, 2, 4, 0),
  List(0, 1, 3, 4, 0),
  List(0, 2, 3, 4, 0),
  List(1, 2, 4, 0, 1),
  List(1, 3, 4, 0, 1),
  List(3, 4, 0, 1, 3),
  List(3, 4, 0, 2, 3),
  List(3, 2, 3, 2, 3),
  List(3, 4, 3, 2, 3),
  List(3, 2, 3, 4, 3),
  List(3, 4, 3, 4, 3),
  List(2, 3, 4, 0, 2),
  List(2, 4, 0, 1, 2),
  List(2, 3, 2, 3, 2),
  List(2, 3, 4, 3, 2)
)

val unique = cycles.filter(_.toSet.size == 4).map(canonicalize).toSet

unique foreach println

输出:

List(0, 1, 2, 4, 0)
List(0, 1, 3, 4, 0)
List(0, 2, 3, 4, 0)

canonicalize的逐行示例:

  1. tail删除重复的顶点:[2, 1, 0, 4, 2] -> [1, 0, 4, 2]
  2. splitAt找到最小顶点并切割列表:[1, 0, 4, 2] -> ([1], [0, 4, 2])
  3. a ++ b重建轮换列表:[0, 4, 2, 1]
  4. :+将最小顶点附加到末尾:[0, 4, 2, 1, 0]

答案 2 :(得分:0)

  1. 从列表中删除最后一个元素(这是多余的)
  2. 滚动列表以从最小的ID开始
  3. 按长度最短的优先排序循环
  4. 您现在可以使用词法匹配(如果loop [i]包含任何loop [0..i-1]->将其删除)
相关问题