问题描述
-
给定的顶点
V
,可以被视为命名为"命题"。 -
给定权重:
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。
之后出现。- 给定一个加权定向的多编码(多个编码(,最多有2个平行边缘...一个顶点只需要一次包含另一个顶点,并且只能使另一个顶点无效,
G = (V, E)
E = (V, V, W)
- 或以定向循环图形为无自动宽的图形,而唯一的循环直接在一个顶点和另一个顶点之间形成。重量更改为:
data W
= Requires -- ^ Denotes that a "proposition" depends on another.
| InvalidatedBy -- ^ Denotes that a "proposition" is invalidated by another.
鉴于顶点可能不止一次在订购中发生...如何从这样的图形构建线性订购?
另外,如果线性排序的尾部以顶点V结束,该顶点是由于另一个顶点无效的,则如果订购的头部以v。
开始,则可能会省略它一些所需的属性是:
- 最小性 - 顶点的重复应尽可能少
- 稳定性 - 排序应与在构造图的同一"级别"上的顶点之间的顺序尽可能相似
- 运行时复杂性 - 顶点的数量不是很高,但仍然……运行时复杂性应尽可能低。
如果各种算法在不同程度上满足这些算法,我很想看到所有这些都会有所交易。
欢迎用任何语言或伪代码编写的算法。示例图:
示例图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]
幼稚实施
幼稚的实现通过从没有传入边缘的所有节点开始构建线性排序,对于所有这些节点:
- 获取所有传出的边缘
- 通过要求/无效的分区
- 构建"需要"的线性排序,并将其首先构建
- 添加当前节点
- 构造"无效"的线性排序并添加。
这是此描述的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描述的算法:
给定一个有向的环状图(DCG(,其中形式的边缘:
(f, t)
表示f
必须在订购中t
之前。在1。
中计算DCG的将每个
condensation
中的每个ssc转。计算3。
中图的顶部。连接计算的排序。
condensation
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
无效1
,2
取决于。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..n]
[1..n] ++ [n-1..1]
-
通过拓扑结合结合了强烈连接的组件。现有的算法在线性时间中以拓扑排序的定向钩形图。