需要协助算法才能找到DAG中的最大路径

时间:2012-02-05 23:57:02

标签: c++ algorithm

假设我有这个Directed Acyclic Graph (DAG),其中每个节点(除了底行中的节点除外)有一个有向边到它下面的两个节点:

        7
      3   8
    8   1   0
  2   7   4   4
4   5   2   6   5

我需要找到通过此DAG的路径,其中节点权重的总和最大化。您只能从此树中的节点向左或向右对角移动。因此,例如,7,3,8,7,5将在此树中给出最大路径。

输入文件包含以这种方式格式化的DAG

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

我的问题是,哪种算法最适合找到最大路径,以及如何用C ++表示这棵树?

节点权重是非负的。

4 个答案:

答案 0 :(得分:13)

我用int s的向量向量表示这个三角形。

从底行开始,比较每对相邻的数字。拿一个较大的一个并将其添加到该对上方的数字:

 5 3             13  3
  \
7 8 6  becomes  7  8  6
^ ^

                  13 3               13 11
                     /
Next iteration   7  8  6   becomes  7  8  6  etc.
                    ^  ^

按照自己的方式到达顶部,完成后,三角形的尖端将包含最大的总和。

答案 1 :(得分:1)

二维数组可以正常工作。您可以使用广度优先遍历来处理此问题,并使用该节点的最大路径总和标记每个访问节点。

例如:

  • 7只能从7开始。
  • 3标记为10,8标记为15.
  • 8标有18(10 + 8),1标有11,后标有16,0标有15。

当标记叶节点时,快速浏览它们以查看哪个是最大的。然后,通过比较当前节点的权重,父节点的权重和边缘权重来开始回溯。

答案 2 :(得分:0)

<强>扰流板

如果您想自己解决此问题,请不要阅读代码。


你可以解决它的一种方法是将数据转换为树(实际上是图形)并编写一个递归算法,通过将树缩小为更小的子树来找到通过树的最大路径(直到你只有一棵树)一个节点)并从那里开始上升。

我非常喜欢递归算法和使用树,所以我继续编写了一个程序来实现它:

#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>

using namespace std;

struct node {
    node(int i, node* left = NULL, node* right = NULL) : data(i), left(left), right(right) { }

    node* left, *right;
    int data;
};

/*
      tree:

        7
      3   8
    8   1   0
  2   7   4   4
4   5   2   6   5

*/

std::vector<node*> maxpath(node* tree, int& sum) {
    if (!tree) {
        sum = -1;
        return std::vector<node*>();
    }

    std::vector<node*> path;

    path.push_back(tree);

    if (!tree->left && !tree->right) {
        sum = tree->data;
        return path;
    }

    int leftsum = 0, rightsum = 0;

    auto leftpath = maxpath(tree->left, leftsum);
    auto rightpath = maxpath(tree->right, rightsum);

    if (leftsum != -1 && leftsum > rightsum) {
        sum = leftsum + tree->data;
        copy(begin(leftpath), end(leftpath), back_inserter<vector<node*>>(path));
        return path;
    }

    sum = rightsum + tree->data;
    copy(begin(rightpath), end(rightpath), back_inserter<vector<node*>>(path));
    return path;
}

int main()
{
    // create the binary tree
    // yay for binary trees on the stack
    node b5[] = { node(4), node(5), node(2), node(6), node(5) };
    node b4[] = { node(2, &b5[0], &b5[1]), node(7, &b5[1], &b5[2]), node(4, &b5[2], &b5[3]), node(4, &b5[3], &b5[4]) };
    node b3[] = { node(8, &b4[0], &b4[1]), node(1, &b4[1], &b4[2]), node(0, &b4[2], &b4[3]) };
    node b2[] = { node(3, &b3[0], &b3[1]), node(8, &b3[1], &b3[2]) };

    node n(7, &b2[0], &b2[1]);

    int sum = 0;

    auto mpath = maxpath(&n, sum);

    for (int i = 0; i < mpath.size(); ++i) {
        cout << mpath[i]->data;

        if (i != mpath.size() - 1)
            cout << " -> ";
    }

    cout << endl << "path added up to " << sum << endl;
}

打印

  

7 - &gt; 3 - &gt; 8 - &gt; 7 - &gt; 5

     

路径最多可添加30个

答案 3 :(得分:-4)

最好的算法是

open the file,
set a counter to 0.
read each line in the file.
for every line you read,
   increment the counter.
close the file.
that counter is your answer.

表示树的最佳算法不算什么。因为你实际上并没有做任何需要树再现的事情。