【问题标题】:Project Euler 18欧拉计划 18
【发布时间】:2011-01-23 06:19:39
【问题描述】:

嘿,一直在 Project Euler 工作,这个给我带来了一些问题

从下面三角形的顶部开始,移动到下一行的相邻数字,从上到下的最大总数为 23。

3

7 4

2 4 6

8 5 9 3

即 3 + 7 + 4 + 9 = 23。

找出下面三角形从上到下的最大值:

...

注意:由于只有 16384 条路线,因此可以通过尝试每条路线来解决此问题。然而,第 67 题是同样的挑战,包含 100 行的三角形;不能靠蛮力解决,需要巧妙的方法! ;o)

这是我用来解决它的算法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Problem18
{
    class Program
    {
        static void Main(string[] args)
        {
            string triangle = @"75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23";
            string[] rows = triangle.Split('\n');
            int currindex = 1;
            int total = int.Parse(rows[0]);
            Console.WriteLine(rows[0]);
            for (int i = 1; i < rows.Length; i++)
            {
                string[] array1 = rows[i].Split(' ');
                if (array1.Length > 1)
                {
                    if (int.Parse(array1[currindex - 1]) > int.Parse(array1[currindex]))
                    {
                        Console.WriteLine(array1[currindex - 1]);
                        total += int.Parse(array1[currindex - 1]);
                    }
                    else
                    {
                        Console.WriteLine(array1[currindex]);
                        total += int.Parse(array1[currindex]);
                        currindex++;
                    }
                }
            }
            Console.WriteLine("Total: " + total);
            Console.ReadKey();
        }
    }
}

现在每当我运行它时,它都会出现 1064,仅比解决方案少 10 - 1074

我没有发现算法有任何问题,我手工解决了这个问题,还提出了 1064,任何人都知道解决方案是否错误,我将问题解释错误,或者是否只是存在缺陷算法?

【问题讨论】:

  • 75+64+82+87+82+75+73+28+83+32+91+78+58+73+93 = 1074

标签: c#


【解决方案1】:

这是一个图形描述:

【讨论】:

  • 每行只添加一个数字,而不是两个
  • "then replace the max sum in the rhird row, delete the last"后最后一行的第一项有错误:不能是9而不是16吗??跨度>
【解决方案2】:

这是 belisarius 所描述的自下而上的方法——使用问题 18 中给出的微不足道的三角形——看起来像,以防万一他的帖子中的图片让其他人感到困惑。

      03
    07  04
  02  04  06
08  05  09  03

      03
    07  04
  02  04  06
08  05  09  03
^^^^^^

      03
    07  04
  10  04  06
08  05  09  03
    ^^^^^^

      03
    07  04
  10  13  06
08  05  09  03
        ^^^^^^

      03
    07  04
  10  13  15
  ^^^^^^
08  05  09  03

      03
    20  04
  10  13  15
      ^^^^^^
08  05  09  03

      03
    20  04
  10  13  15
      ^^^^^^
08  05  09  03

      03
    20  19
    ^^^^^^
  10  13  15
08  05  09  03

      23
      ^^
    20  19
  10  13  15
08  05  09  03

【讨论】:

  • 谢谢。我现在意识到我的算法解决了一个稍微不同的三角形。你的更准确
  • @belisarius 但是,你的算法让我找到了这个答案,所以也感谢
【解决方案3】:

你的问题是你的算法是一个贪心算法,总是找到局部最大值。不幸的是,这会导致它错过下面的较高数字,因为它们直接低于较低的数字。例如,如果三角形只有 3 个级别,您的算法将选择 75 + 95 + 47 = 217,而正确答案是 75 + 64 + 82 = 221。

正确的算法将尝试每条路径并选择总和最高的路径,或者自下而上计算路径(这样您就可以避免尝试每条路径,从而更快)。我应该补充一点,自下而上的工作不仅要快得多(O(n^2) 而不是 O(2^n)!),而且更容易编写(我用大约 3 行代码就完成了) .

【讨论】:

  • 您确定自下而上的工作是正确的,并导致正确的结果吗?它不适用于贪婪算法 - gist.github.com/791893(实际上,我不确定你的意思是什么。我可能误解了 :P
  • Kobi:是的,自下而上是正确的(或者至少它让我得到 1074)。你说得对,贪心算法是行不通的。
  • 自下而上只有在您将其实现为缓存算法时才会真正有所帮助,还是我遗漏了什么?不过,这可以非常有效地完成,因为您只需要随时保留有关两行的信息。编辑:我现在在谈论效率
  • 我知道这是旧的,但我今天正在解决这个问题。说明清楚地说“找到下面三角形的从上到下的最大总数”。我知道从底部开始工作会产生不同的结果,但这不是问题所说的。
  • Doug:这仍然有效的原因是它找到了最好的从上到下的路径,它只是没有通过从上到下找到路径。此外,我选择这个答案是正确的,因为它是解释为什么我使用的算法不起作用的最佳答案,并且还详细介绍了正确的算法以及比我使用的算法 [更快] 更准确的算法
【解决方案4】:

你写了一个greedy algorithm,我认为它不符合这里的要求。这里有一个简单的例子来证明这一点:

  1
 2 1
1 1 100 

使用您的算法,总和将达到 4,尽管最优解是 102。

【讨论】:

    【解决方案5】:

    这是一个基于动态规划的好问题。您需要创建一个二维数据结构(如 c++ 中的向量),然后按照 dp 的自下而上的方法。

    公式为dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1])。尝试自己编写代码,如果遇到困难,请查看我的解决方案。

    vector< vector<int> > dp(n); // n is the number of rows
    for (int i = 0 ; i < n; i++){
        for (int j = 0; j <= i; j++){
            cin >> val;
            dp[i].push_back(val);
        }
    }
    for (int i = n - 2 ; i >= 0; i--)
    {
        for (int j = 0; j <= i; j++)
            dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1]);    
    }
    cout << dp[0][0] << endl;   
    return 0;
    }
    

    输入:3 2 4 5 6 8 9

    输出:16

    【讨论】:

      【解决方案6】:

      递归(不一定是最好的)方法:

          static int q18(){
              int matrix[][] = // BIG MATRIX;
              return getMaxPath(matrix, 0, 0, 0);
          }
          static int getMaxPath(int matrix[][], int sum, int row, int col){
              if(row==matrix.length) return sum;
              return Math.max(getMaxPath(matrix, sum+matrix[row][col], row+1, col),
                              getMaxPath(matrix, sum+matrix[row][col], row+1, col+1));
          }
      

      【讨论】:

      • 原因是因为它没有回答问题。问题不是问解决问题 18 的方法,而是问为什么我使用的算法不起作用。在所有其他答案中,他们解释了算法的问题以及解决问题的潜在方法(即不使用贪心算法)。它也不会增加已经给出的答案。我希望这可以解决问题,帮助中心有一个回答问题的页面以获取更多信息。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多