依赖依赖的定向多序的线性顺序允许重复



问题描述

  1. 给定的顶点V,可以被视为命名为"命题"。

  2. 给定权重:

data W
  = Requires     -- ^ Denotes that a "proposition" depends on another.
  | Invalidates  -- ^ Denotes that a "proposition" invalidates another.

在线性排序中,如果A需要B,则B必须在A之前进行,相反,如果A为B,则B必须在A。

之后出现。
  1. 给定一个加权定向的多编码(多个编码(,最多有2个平行边缘...一个顶点只需要一次包含另一个顶点,并且只能使另一个顶点无效,
G = (V, E)
E = (V, V, W)
  1. 或以定向循环图形为无自动宽的图形,而唯一的循环直接在一个顶点和另一个顶点之间形成。重量更改为:
data W
  = Requires      -- ^ Denotes that a "proposition" depends on another.
  | InvalidatedBy -- ^ Denotes that a "proposition" is invalidated by another.

鉴于顶点可能不止一次在订购中发生...如何从这样的图形构建线性订购?

另外,如果线性排序的尾部以顶点V结束,该顶点是由于另一个顶点无效的,则如果订购的头部以v。

开始,则可能会省略它

一些所需的属性是:

  1. 最小性 - 顶点的重复应尽可能少
  2. 稳定性 - 排序应与在构造图的同一"级别"上的顶点之间的顺序尽可能相似
  3. 运行时复杂性 - 顶点的数量不是很高,但仍然……运行时复杂性应尽可能低。

如果各种算法在不同程度上满足这些算法,我很想看到所有这些都会有所交易。

欢迎用任何语言或伪代码编写的算法。

示例图:

示例图1:

B `requires`    A
C `requires`    A
D `requires`    A
E `invalidates` A
F `invalidates` A
G `invalidates` A

使用最小的线性排序:[a,b,c,d,e,f,g]

示例图2:

C `requires`    A
C `invalidates` A
B `requires`    A

最少线性排序:[a,b,c]

示例图3:

B `requires`    A
B `invalidates` A
C `requires`    A
C `invalidates` A

使用最小的线性排序:[a,b,a,c]

幼稚实施

幼稚的实现通过从没有传入边缘的所有节点开始构建线性排序,对于所有这些节点:

  1. 获取所有传出的边缘
  2. 通过要求/无效的分区
  3. 构建"需要"的线性排序,并将其首先构建
  4. 添加当前节点
  5. 构造"无效"的线性排序并添加。

这是此描述的Haskell实现:

import Data.List (partition)
import Data.Maybe (fromJust)
import Control.Arrow ((***))
import Data.Graph.Inductive.Graph
fboth :: Functor f => (a -> b) -> (f a, f a) -> (f b, f b)
fboth f = fmap f *** fmap f
outs :: Graph gr => gr a b -> Node -> (Adj b, a)
outs gr n = let (_, _, l, o) = fromJust $ fst $ match n gr in (o, l)
starts :: Graph gr => gr a b -> [(Adj b, a)]
starts gr = filter (not . null . fst) $ outs gr <$> nodes gr
partW :: Adj W -> (Adj W, Adj W)
partW = partition ((Requires ==) . fst)
linearize :: Graph gr => gr a W -> [a]
linearize gr = concat $ linearize' gr <$> starts gr
linearize' :: Graph gr => gr a W -> (Adj W, a) -> [a]
linearize' gr (o, a) = concat req ++ [a] ++ concat inv
  where (req, inv) = fboth (linearize' gr . outs gr . snd) $ partW o

然后,可以通过删除相等的连续类似地进行优化订购:

-- | Remove consecutive elements which are equal to a previous element.
-- Runtime complexity: O(n), space: O(1)
removeConsequtiveEq :: Eq a => [a] -> [a]
removeConsequtiveEq = case
  []    -> []
  [x]   -> [x]
  (h:t) -> h : ug h t
  where
    ug e = case
      []     -> []
      (x:xs) | e == x    ->     ug x xs
      (x:xs) | otherwise -> x : ug x xs

编辑:使用DCG,SCC和TopSort

使用@cirdec描述的算法:

  1. 给定一个有向的环状图(DCG(,其中形式的边缘: (f, t)表示f必须在订购中 t之前。

  2. 在1。

  3. 中计算DCG的condensation
  4. 将每个 condensation中的每个ssc转。

  5. 计算3。

  6. 中图的顶部。
  7. 连接计算的排序。

in haskell:

{-# LANGUAGE LambdaCase #-}
import Data.List (nub)
import Data.Maybe (fromJust)
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Data.Graph.Inductive.NodeMap
import Data.Graph.Inductive.Query.DFS
data MkEdge = MkEdge Bool Int Int
req = MkEdge True
inv = MkEdge False
toGraph :: [MkEdge] -> [(Int, Int, Bool)] -> Gr Int Bool
toGraph edges es = run_ empty nm
  where ns = nub $ edges >>= (MkEdge _ f t) -> [f, t]
        nm = insMapNodesM ns >> insMapEdgesM es
-- | Make graph into a directed cyclic graph (DCG).
-- "Requires"    denotes a forward  edge.
-- "Invalidates" denotes a backward edge.
toDCG :: [MkEdge] -> Gr Int Bool
toDCG edges = toGraph edges $
  ((MkEdge w f t) -> if w then (t, f, w) else (f, t, w)) <$> edges
-- | Make a palindrome of the given list by computing: [1 .. n] ++ [n - 1 .. 1].
-- Runtime complexity: O(n).
palindrome :: [a] -> [a]
palindrome = case
  [] -> []
  xs -> xs ++ tail (reverse xs)
linearize :: Gr Int a -> [Int]
linearize dcg = concat $ topsort' scc2
  where scc  = nmap (fmap (fromJust . lab dcg)) $ condensation dcg
        scc2 = nmap palindrome scc

图形g2

g2 = [ 2 `req` 1
     , 2 `inv` 1
     , 3 `req` 1
     , 3 `inv` 1
     , 4 `req` 1
     , 5 `inv` 1
     ]
> prettyPrint $ toDCG g2
1:2->[(False,2)]
2:1->[(True,1),(True,3),(True,4)]
3:3->[(False,2)]
4:4->[]
5:5->[(False,2)]
> prettyPrint $ condensation $ toDCG g2
1:[5]->[((),2)]
2:[1,2,3]->[((),3)]
3:[4]->[]
> linearize $ toDCG g2
[5,2,1,3,1,2,4]

此顺序既不是最小也不有效,因为订购违反了依赖关系。5无效12取决于。2无效1 4取决于。

有效且最小的排序为:[1,4,2,1,3,5]。通过将列表转移到右侧,我们将获得[5,1,4,2,1,3],这也是有效的订购。

如果图形的方向翻转,则排序变为:[4,2,1,3,1,2,5]。这也不是有效的订购...在边界上,5可以发生,然后是4,但是5无效1 4依赖于。

我相信以下算法会在线性时间中找到最小的顶点:

  1. 将图形分解为其紧密连接的组件。现有算法在线性时间内执行此操作。

  2. 在每个牢固连接的组件中,每个节点都需要在其他节点之前和之后列出每个节点。在以下顺序中列出每个强连接组件的节点[1..n] [1..n] ++ [n-1..1]

  3. 通过拓扑结合结合了强烈连接的组件。现有的算法在线性时间中以拓扑排序的定向钩形图。

最新更新