【问题标题】:Given a DAG, the length of the longest path and the node in which it ends, how do I retrace my steps so I can print each node of the longest path?给定一个 DAG,最长路径的长度和它结束的节点,我如何回溯我的步骤以便打印最长路径的每个节点?
【发布时间】:2021-09-25 07:55:09
【问题描述】:

我正在解决一个问题,即在给定平行六面体列表的情况下找到可以相互存储的最多平行六面体。

我的方法是用邻接表表示图,进行拓扑排序,然后为拓扑数组中的每个节点“放松”边,给我最长的路径。

以下是代码,但我认为这对问题无关紧要。

typedef struct Edge {
int src;            /* source node  */
int dst;            /* destination node  */
struct Edge *next;
} Edge;


int maxend;  //node in which the longest path ends
int mp; // longest path

for (int i = 0; i < G.n; i++)
{   
    int j = TA[i];             //TA is the topological sorted array
    if (g->edges[j] != NULL) 
    {                           
        if(DTA[j] == -1) DTA[j] = 0; 
        
        Edge* tmp = G.edges[j];
    
        while (tmp != NULL)
        {   
            if(DTA[tmp->src] >= DTA[tmp->dst]){     //DTA is the array that keeps track of the maximum distance of each node in TA
                DTA[tmp->dst] = DTA[tmp->src]+1;   
                if (DTA[tmp->dst] > mp) {
                    mp = DTA[tmp->dst];
                    maxend = tmp->dst;
                }
            }    
            tmp = tmp->next;
        }
    }
}     

最后我得到了最长路径的长度和所述路径结束的节点,但是如何有效地重新创建路径?

如果平行六面体A包含平行六面体B并且平行六面体B包含平行六面体C,这意味着平行六面体A也包含平行六面体C,这意味着每条边的权重为1并且最长路径开始的顶点具有路径中最远的节点他的邻接列表。

我想到了 3 个解决方案,但没有一个看起来很棒。

  1. 迭代每个权重为 0 的顶点的边(所以没有前辈),如果有选择,请避免选择将其与最远节点连接的边(如前所述,起始节点和结束节点之间的最短路径节点将是 1)

  2. 在跟踪拓扑排序数组中每个节点的最大距离的数组中:从表示我们找到的最远节点的索引开始,看前一个节点是否有兼容的距离(如,前一个节点有1距离小于最远节点)。如果是,请检查它的邻接列表以查看最远节点是否在其中(因为如果最远节点的距离为 10,则可能有多个距离为 9 但未连接到它的节点)。重复直到我们到达路径的根。

  3. 到目前为止最可能的候选者,创建一个指针数组来跟踪每个节点的“最大”父节点。在上面的代码中,每当一个节点的最大距离发生变化时,这意味着它的父节点(如果有的话)比前一个父节点的距离更长,这意味着我们可以更改与当前节点关联的最大父节点。

编辑:我最终只是分配了一个新数组,每次更新节点的权重( DTA[tmp->src] >= DTA[tmp->dst] )我还将源边的编号存储在目标边的单元格。

【问题讨论】:

  • 你不能从最大的盒子开始,然后是第二大的,然后是第三大的......?
  • @NealBurns 是的。这将是对这个问题的明智的第一次攻击。亲吻总是好的。
  • @NealBurns 我相信如果盒子都是立方体,您的简单方法将给出最佳答案。否则,它可能会错过不规则六面体的最佳布置(我假设 OP 正在考虑 - 他没有说)
  • 是的,我更新了帖子。盒子是不能旋转的平行六面体
  • 恐怕我不明白你所说的'给定一个DAG,最长的路径和它结束的节点(... )'。如果给定最长的路径,那么在该路径上打印节点有什么问题??

标签: c algorithm graph-theory


【解决方案1】:

我假设图边 u

我建议你转储拓扑排序。而是:

SET weight of every edge to -1
LOOP
   LOOP over leaf nodes ( out degree zero, box too small to contain others )
       Run Dijkstra algorithm ( gives longest path, with predecessors )
       Save length of longest path, and path itself
   SAVE longest path
   REMOVE nodes on longest path from graph
   IF all nodes gone from graph
        OUTPUT saved longest paths ( lists of nested boxes )
        STOP

这被称为“贪心”算法。不能保证给出最佳结果。但它又快又简单,总能给出合理的结果,而且常常给出最优的结果。

【讨论】:

  • 我的印象是 Dijkstra 不适用于负边缘,这是一种特殊情况,因为权重 1 基本上意味着未加权?
  • 寻找最长路径的标准方法是使用负权重运行 Dijkstra。无法处理的是一些 -ve 和一些 +ve en.wikipedia.org/wiki/Longest_path_problem
【解决方案2】:

I think this solves it,除非有什么我不明白的地方。

如果将边权重设为负值,则 DAG 中权重最高的路径等同于权重最低的路径。然后就可以直接应用 Dijkstra 算法了。

加权图中两个给定顶点 s 和 t 之间的最长路径 G 与图中的最短路径相同 -G 从 G 派生 将每个权重都改为否定。

这甚至可能是 Dijkstra 的一个特例,它更简单……不确定。

要检索最长的路径,请从末尾开始并向后走:

  1. 从 DTA 最大的顶点开始V_max
  2. 找到以V_max (edge-&gt;dest = V_max) 结束的边
  3. 找到 DTA 值比最大值 (DTA[Src_max] == DTA[V_max] - 1) 小 1 的边 Src_max
  4. 递归重复此操作,直到不再有源顶点

为了提高效率,您可以在向下的过程中反转边缘的端点,然后沿着路径返回起点。这样每个反向步骤都是 O(1)。

【讨论】:

    【解决方案3】:

    我认为选项 3 最有希望。您可以使用 DSF 从所有根顶点(没有传入边的顶点)开始搜索最长路径,并增加遇到的每个顶点的“最大距离”。

    这是一个非常简单的解决方案,但它可能会多次遍历某些路径。例如,对于边 (a,f), (b,c), (c,f), (d,e), (e,c)

    a------------f
                /
       b----c--/
           /
    d--e--/
    

    (全部向右) 起始顶点是a、b和d,边(c,f)将被遍历两次,顶点f距离将被更新3次。如果我们将字母表的其余部分附加到一个简单的链中,

    a------------f-----g--  -  -  ---y---z 
                /
       b----c--/
           /
    d--e--/
    

    从 f 到 z 的整个链也可能会被遍历 3 次。

    您可以通过分离阶段并修改它们之间的图形来避免这种情况:在找到所有起始顶点 (a, b, d) 后,增加每个可用顶点与这些 (f, c, e) 的距离,然后删除从图中开始顶点及其边缘 - 只要还有一些边缘,就重新迭代。
    这将在第一步之后转换示例图,如下所示:

                 f-----g--  -  -  ---y---z 
                /
            c--/
           /
       e--/
    

    我们可以看到,所有的交汇点(c 和 f)都会等到找到最长的到它们的路径,然后再进行进一步的分析。

    这需要迭代寻找起始顶点,这可能很耗时,除非您进行一些预处理(例如,计算每个顶点的所有传入边并将顶点存储在某种排序数据结构中,例如整数索引的多图或简单的最小堆。)

    问题仍然悬而未决,与在特定图中多次遍历公共路径的某些最终部分相比,截断图并重新扫描新根顶点的整个开销是否会带来净收益...

    【讨论】:

      猜你喜欢
      • 2011-03-08
      • 2014-06-24
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 1970-01-01
      • 1970-01-01
      • 2019-08-07
      • 1970-01-01
      相关资源
      最近更新 更多