Project Euler问题67:找到100行三角形中的最大成本路径

时间:2011-07-01 22:12:00

标签: data-structures puzzle

Project Euler's problem 67中,给出了一个三角形,它包含100行。例如,

        5
      9  6
    4   6  8
  0   7  1   5

I.e. 5 + 9 + 6 + 7 = 27.

现在我必须在给定的100行三角形中找到从上到下的最大总数。

我在考虑应该使用哪种数据结构,以便有效地解决问题。

5 个答案:

答案 0 :(得分:4)

您希望将其存储为directed acyclic graph。节点是三角形数组的条目,并且ij的箭头如果j低于i的左下一行。< / p>

现在您想在此图中找到maximum weight directed path(顶点权重之和)。一般来说,这个问题是NP完全的,然而,正如templatetypedef所指出的,DAG有一些有效的算法; here's one

algorithm dag-longest-path is
    input: 
         Directed acyclic graph G
    output: 
         Length of the longest path

    length_to = array with |V(G)| elements of type int with default value 0

    for each vertex v in topOrder(G) do
        for each edge (v, w) in E(G) do
            if length_to[w] <= length_to[v] + weight(G,(v,w)) then
                length_to[w] = length_to[v] + weight(G, (v,w))

    return max(length_to[v] for v in V(G))

为了使这项工作,您需要将路径的length加权为目标节点的大小(因为所有路径都包含源,这很好)。

答案 1 :(得分:1)

您使用的是哪种语言?

多维数组可能是存储值的最佳方法,然后根据语言的不同,您可以选择存储指针或引用数组中的位置。

答案 2 :(得分:1)

为了建立@Matt Wilson的答案,使用二维数组来保存数字将是一个相当简单的解决方案。在您的情况下,您将编码三角形

      5
    9  6
  4   6  8
0   7  1   5

作为数组

[5][ ][ ][ ]
[9][6][ ][ ]
[4][6][8][ ]
[0][7][1][5]

从这里开始,位置(i,j)处的节点在(i + 1,j)和(i + 1,j + 1)处具有子节点,在位置(i-1,j)处具有父节点,并且(i - 1,j - 1),假设这些指数有效。

这种方法的优点是,如果你的三角形有高度N,这种方法所需的空间是N 2 ,这只是N(N + 1)/ 2空间的两倍需要实际存储元素。像显式图这样的链接结构肯定会使用更多的内存。

答案 3 :(得分:0)

我认为这是项目欧拉问题。

无法用二叉树表示。任何类型的图形都是过度的,尽管问题可以通过有向非循环图中的最长路径算法来解决。编辑:没关系,只有在边加权时才有用,而不是节点。

二维向量(例如vector<vector<int> >)足以表示这样的三角形,并且使用这种表示有一种直接的解决方案。

答案 4 :(得分:0)

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>

int main() { 
    std::vector<std::vector<int> > lines;
    lines.resize(100);
    std::ifstream input("triangle.txt");

    for (int i = 0; i < 100; i++) {
        for (int j = 0; j < i + 1; j++) {
            std::string number_string;
            input >> number_string;
            std::istringstream temp(number_string);
            int value = 0;
            temp >> value;
            lines[i].push_back(value);
        }
    } 
    std::vector<int> path1;
    path1.resize(100);
    std::vector<int> path2;
    path2.resize(100);

    for (int i = 0;i < 100;i++) 
        path1[i] = lines[99][i];

    for (int i = 98; i >= 0;i--) {  
        for(int j = 0;j < i+1;j++) {
            if(path1[j] > path1[j + 1]){
                path2[j] = path1[j] + lines[i][j];
            } else{
                path2[j] = path1[j + 1] + lines[i][j];
            }
        }
        for (int i = 0;i < 100;i++) 
            path1[i] = path2[i];
    }
    std::cout << path1[0] << std::endl;
}