Algorithm 是否存在只穿过每种颜色一次的路径?

Algorithm 是否存在只穿过每种颜色一次的路径?,algorithm,graph-theory,network-flow,Algorithm,Graph Theory,Network Flow,我有一个有方向的彩色图(每个节点都有一种颜色),我想知道从节点a到节点B的路径是否存在,这样路径最多只通过每种颜色一次 我认为这个问题可以用网络流来描述。如果重复某个节点,则可以在使流为0或无穷大的相同颜色的节点上施加惩罚 谢谢 只需执行普通DFS,但也要保留颜色列表和每个颜色的布尔值。如果要访问具有某种颜色的节点,而相应的布尔值为false,请将其设置为true并访问它;否则不要访问该节点并保持递归。如果你在没有到达B的情况下终止,那么显然没有路径 编辑:如果某些选择的路径不起作用,并且递归回

我有一个有方向的彩色图(每个节点都有一种颜色),我想知道从节点a到节点B的路径是否存在,这样路径最多只通过每种颜色一次

我认为这个问题可以用网络流来描述。如果重复某个节点,则可以在使流为0或无穷大的相同颜色的节点上施加惩罚


谢谢

只需执行普通DFS,但也要保留颜色列表和每个颜色的布尔值。如果要访问具有某种颜色的节点,而相应的布尔值为false,请将其设置为true并访问它;否则不要访问该节点并保持递归。如果你在没有到达B的情况下终止,那么显然没有路径


编辑:如果某些选择的路径不起作用,并且递归回溯,请重置与回溯过去的节点的颜色相关联的布尔值。

假设您希望使用搜索算法,则最有可能使用深度优先回溯,从图中删除(或标记为已访问)您访问的每个节点

将为访问的颜色保留一个哈希表,以便在已知或未知的情况下快速检查找到的每种新颜色(或者如果不能使用单独的结构,而只能在图形上附加属性,则检查图形上从a到C[=当前]或从C到a[无所谓]的访问路径)

对于回溯,您可以在从导致死端(即无法到达B)的传出链接回溯到节点后检查下一个传出链接。这假设链接具有某种隐式排序(也就是说,当您有一个节点和它的某个其他传出链接时,您可以请求下一个链接,并检查它是否是传出链接,或者请求下一个链接,直到没有更多可用的链接为止,当您在回溯时通过该链接返回时))


但是,应该有更好的算法对图形进行一些(可并行化)预处理,并在节点和/或链接上附加值,以帮助从给定颜色或任何颜色进行搜索

这是NP难的,因为从“具有禁止对的路径”的特例中进行缩减要求所有禁止对不相交的问题。只需为每一对被禁止的颜色分配一些颜色。“禁止对路径”是一个众所周知的NP难问题(即使在不相交对的情况下,它仍然是NP难问题)。在Garey和Johnson的书中,它有一个标识符“GT54”

但如果非唯一颜色的数量(
k
)是一个小常数,则可以应用时间复杂度为O(| E |*2*k)的改进BFS算法

在这里,我解释这个BFS算法(从简化版开始):

路径访问的所有节点的颜色都应编码到位集中,例如,如果我们有3种可用颜色(红色、绿色、蓝色)和一条访问绿色节点的路径,则将其编码为
010
;在该路径也访问红色节点之后,它被编码为
011
。路径颜色与上次访问的节点一起存储在BFS队列中

每个节点应该为每个颜色组合存储一些“已访问”标志。假设示例中有三种颜色,每个未访问的节点将存储8个布尔值为“false”。使用红/绿路径访问此节点后,其“已访问”标志应更改为以下内容:

index.bool  index.dec  visited_flag
       000          0         false
       001          1         false
       010          2         false
       011          3          true
       100          4         false
       101          5         false
       110          6         false
       111          7         false
如果算法在处理具有相同颜色组合的路径时遇到相同的节点,它应该忽略它,因为“真”访问标志

BFS算法主循环的伪代码可以重写为:

 while Q is not empty:

     (u, c) = Q.dequeue()

     for each node n that is adjacent to u:
         if (c & n.color) == 0 && n.visited[c] == false:
             n.visited[c] = true
             Q.enqueue((n, c | n.color))
算法照常终止:到达目的地(路径存在)或BFS队列变为空(路径不存在)


该算法最坏情况下的时间复杂度为O(| E |*2k)。但它仍在做大量的冗余工作。由于在BFS算法中,较短(且颜色较少)的路径被认为比较长的路径更早,因此很可能首先使用红色路径访问某个节点,然后使用绿色路径访问该节点,然后使用红色/绿色路径访问该节点。在这种情况下,处理这条红/绿路径无法带来任何改进。这意味着我们可以在处理绿色路径的同时,将红色/绿色标记为“已访问”,从而加快算法的速度。这种优化不是免费的:它需要在处理每个路径/节点组合时标记几个标志,并且它将最坏情况的时间复杂度增加到O(| E |*2*k)。但所有额外的工作都是在节点内部本地完成的。另外,如果所有2k标志都适合单个CPU寄存器,那么所有这些工作都可以通过按位逻辑操作并行完成。

您确定这一点吗?如果我有一个带有红色和蓝色节点的图,我遇到的第一个蓝色节点不在所需路径上,但第二个蓝色节点在所需路径上,该怎么办。在这种情况下,第二个蓝色将被丢弃,因为第一个…?@PK5144啊,是的,对不起。将使用caveatOk的解决方案进行编辑,这很有意义。为了澄清,DFS的运行时通常是O(E)。使用回溯,最坏的情况不是指数型的,还是我们可以保证更好?@PK5144“回溯”只是指“展开”递归-即,如果节点的子路径没有正确地指向B,则递归将返回到其前一个节点。此时,取消标记与此节点颜色关联的布尔值。所以复杂性是不变的(假设查找颜色是O(1),这可以通过预索引/哈希表来完成,正如George所建议的)一种更简单的表达方式是说“保留一组访问过的颜色”。集合成员资格是布尔条件。对于密集集,位图很好。对于稀疏集,哈希表很好。两者都支持常量时间测试/添加/删除操作。前者以有许多复杂的算法来计算而闻名,而后者则以被数学证明为不可解而闻名。这是一个NP完全问题。除非你的计划是对它进行暴力,否则它是非常不平凡的,这将是O(n!)。@BaconBits:我们不是在要求满足条件的最短路径