最大路径总和在带有素数检查的三角形中

时间:2017-05-18 14:25:57

标签: c# algorithm primes

我得到了这个算法任务:

您将在下方输入三角形,您需要根据以下给定规则找到最大数字总和;

  1. 您将从顶部开始向下移动到相邻的数字,如下所示。
  2. 您只能向下和对角走路。
  3. 您只能走过非PRIME NUMBERS。

         1
        8 4
      2  6  9
     8  5  9  3
    
  4. 正如您所看到的,这有几条符合NOT PRIME NUMBERS规则的路径; 1> 8> 6> 9,1> 4> 6> 9,1> 4> 9> 9 1 + 8 + 6 + 9 = 24.正如您所看到的那样,1,8,6,9都不是PRIME NUMBERS并且在这些数字上行走会产生最大值。

    根据上述规则,以下输入的最大总和是多少?这意味着请将此金字塔作为输入(作为代码中的文件或常量)用于实现,并使用它来解决。

                                      215
                                   193 124
                                 117 237 442
                               218 935 347 235
                             320 804 522 417 345
                           229 601 723 835 133 124
                         248 202 277 433 207 263 257
                       359 464 504 528 516 716 871 182
                     461 441 426 656 863 560 380 171 923
                   381 348 573 533 447 632 387 176 975 449
                 223 711 445 645 245 543 931 532 937 541 444
               330 131 333 928 377 733 017 778 839 168 197 197
            131 171 522 137 217 224 291 413 528 520 227 229 928
          223 626 034 683 839 053 627 310 713 999 629 817 410 121
        924 622 911 233 325 139 721 218 253 223 107 233 230 124 233
    

    请注意,每个节点此处只有两个子节点(最底层节点除外)。举个例子,你可以步行215到124(因为193是素数)然后从124步行到237或442.从124你不能去117,因为它不是124的直接孩子。

    我知道解决这个问题有不同的方法可以

    • 强力方法

    • 动态编程方法

    由于其效率,我使用了动态编程方法:

    using System;
    
    class Program
    {
        static void Main(string[] args)
        {
    
    
            //get input
            var input = GetInput();
    
            string[] arrayOfRowsByNewlines = input.Split('\n');
    
            var tableHolder = FlattenTheTriangleIntoTable(arrayOfRowsByNewlines);
    
            var result = WalkThroughTheNode(arrayOfRowsByNewlines, tableHolder);
    
            Console.WriteLine($"The Maximum Total Sum Of Non-Prime Numbers From Top To Bottom Is:  {result[0,0]}");
    
            Console.ReadKey();
        }
    
        private static string GetInput()
        {
    
                const string input = @"   215
                                       193 124
                                      117 237 442
                                    218 935 347 235
                                  320 804 522 417 345
                                229 601 723 835 133 124
                              248 202 277 433 207 263 257
                            359 464 504 528 516 716 871 182
                          461 441 426 656 863 560 380 171 923
                         381 348 573 533 447 632 387 176 975 449
                       223 711 445 645 245 543 931 532 937 541 444
                     330 131 333 928 377 733 017 778 839 168 197 197
                    131 171 522 137 217 224 291 413 528 520 227 229 928
                  223 626 034 683 839 053 627 310 713 999 629 817 410 121
                924 622 911 233 325 139 721 218 253 223 107 233 230 124 233";
            return input;
        }
    
        private static int[,] WalkThroughTheNode(string[] arrayOfRowsByNewlines, int[,] tableHolder)
        {
            // walking through the non-prime node
            for (int i = arrayOfRowsByNewlines.Length - 2; i >= 0; i--)
            {
                for (int j = 0; j < arrayOfRowsByNewlines.Length; j++)
                {
                    //only sum through the non-prime node
                    if ((!IsPrime(tableHolder[i, j])))
                    {
                        tableHolder[i, j] = Math.Max(tableHolder[i, j] + tableHolder[i + 1, j],
                            tableHolder[i, j] + tableHolder[i + 1, j + 1]);
                    }
                }
            }
            return tableHolder;
        }
    
        private static int[,] FlattenTheTriangleIntoTable(string[] arrayOfRowsByNewlines)
        {
            int[,] tableHolder = new int[arrayOfRowsByNewlines.Length, arrayOfRowsByNewlines.Length + 1];
    
            for (int row = 0; row < arrayOfRowsByNewlines.Length; row++)
            {
                var eachCharactersInRow = arrayOfRowsByNewlines[row].Trim().Split(' ');
    
                for (int column = 0; column < eachCharactersInRow.Length; column++)
                {
                    int number;
                    int.TryParse(eachCharactersInRow[column], out number);
                    tableHolder[row, column] = number;
                }
            }
            return tableHolder;
        }
    
        public static bool IsPrime(int number)
        {
            // Test whether the parameter is a prime number.
            if ((number & 1) == 0)
            {
                if (number == 2)
                {
                    return true;
                }
                return false;
            }
    
            for (int i = 3; (i * i) <= number; i += 2)
            {
                if ((number % i) == 0)
                {
                    return false;
                }
            }
            return number != 1;
        }
    
    
    
    
    }
    

    有人可以帮助我查看代码,看看是否有更好的解决方法。

5 个答案:

答案 0 :(得分:1)

素数检查效率不高,但对于这么小的数字并不重要。您的动态编程方法很好,但是素数的逻辑中存在错误。您只检查父节点是否为素数。因此,如果两个子节点都是素数,则父节点永远不能成为有效路径的一部分,但如果父节点不是素数,则仍然会提升两个素数中较大的一个+父值。如何解决它:

  1. 在最低级别:如果数字是素数,则将其设置为-1。

  2. 在下一个级别:如果数字是素数,或两个孩子都是&lt; 0将其设置为-1,否则将数字+最大值与之前一样。

  3. 如果顶部节点的值为-1,则没有有效的路径到底部,它是最大路径的总和而没有踩到素数

答案 1 :(得分:1)

对于这个特定问题,您的方法似乎很合理。这个问题是一个更普遍的问题的简化版本;你可以考虑解决更普遍的问题。

  • 构造有向图,其中节点是三角形的元素,有向边从节点到达可以到达的节点。

  • 创建一个起始节点,边缘到达三角形的顶部,以及一个停止节点,边缘从每个底部节点到达它。

  • 删除转到作为素数的节点的所有边。

  • 边缘的权重是它指向的节点的值;停止节点的值为零。

  • 现在您有一个加权有向无环图。使用标准最小路径查找算法查找从开始到停止节点的最低成本路径。

  • 最低成本是您要查找的值的负数。

此技术适用于任何加权有向无环图,而不仅仅是三角形图。

答案 2 :(得分:0)

这对我有用

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

internal static class Program
{
    /// <summary>
    /// </summary>
    public static Dictionary<int, bool> PrimeCache = new Dictionary<int, bool>();

    private static void Main(string[] args)
    {
        var result = GetInput()
            .TransformInputToArray()
            .TransformTo2Darray()
            .ResetAllPrimeNumbers()
            .WalkThroughTheNode();

        Console.WriteLine($"The Maximum Total Sum Of Non-Prime Numbers From Top To Bottom Is:  {result}");
        Console.ReadKey();
    }

    /// <summary>
    ///     Prepare input
    /// </summary>
    /// <returns></returns>
    private static string GetInput()
    {
        const string input = @" 215
                                   193 124
                                  117 237 442
                                218 935 347 235
                              320 804 522 417 345
                            229 601 723 835 133 124
                          248 202 277 433 207 263 257
                        359 464 504 528 516 716 871 182
                      461 441 426 656 863 560 380 171 923
                     381 348 573 533 447 632 387 176 975 449
                   223 711 445 645 245 543 931 532 937 541 444
                 330 131 333 928 377 733 017 778 839 168 197 197
                131 171 522 137 217 224 291 413 528 520 227 229 928
              223 626 034 683 839 053 627 310 713 999 629 817 410 121
            924 622 911 233 325 139 721 218 253 223 107 233 230 124 233";
        return input;
    }

    /// <summary>
    ///     Transform the input to array
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    private static string[] TransformInputToArray(this string input)
    {
        return input.Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
    }

    /// <summary>
    ///     Transform the array to 2D array
    /// </summary>
    /// <param name="arrayOfRowsByNewlines"></param>
    /// <returns></returns>
    private static int[,] TransformTo2Darray(this string[] arrayOfRowsByNewlines)
    {
        var tableHolder = new int[arrayOfRowsByNewlines.Length, arrayOfRowsByNewlines.Length + 1];

        for (var row = 0; row < arrayOfRowsByNewlines.Length; row++)
        {
            var eachCharactersInRow = arrayOfRowsByNewlines[row].ExtractNumber();

            for (var column = 0; column < eachCharactersInRow.Length; column++)
                tableHolder[row, column] = eachCharactersInRow[column];
        }
        return tableHolder;
    }

    /// <summary>
    ///     Extract Number from the row
    /// </summary>
    /// <param name="rows"></param>
    /// <returns></returns>
    private static int[] ExtractNumber(this string rows)
    {
        return
            Regex
                .Matches(rows, "[0-9]+")
                .Cast<Match>()
                .Select(m => int.Parse(m.Value)).ToArray();
    }

    /// <summary>
    ///     Reset all the prime number to zero
    /// </summary>
    /// <param name="tableHolder"></param>
    /// <returns></returns>
    private static int[,] ResetAllPrimeNumbers(this int[,] tableHolder)
    {
        var length = tableHolder.GetLength(0);
        for (var i = 0; i < length; i++)
        {
            for (var j = 0; j < length; j++)
            {
                if (tableHolder[i, j] == 0) continue;
                if (IsPrime(tableHolder[i, j]))
                    tableHolder[i, j] = 0;
            }
        }
        return tableHolder;
    }

    /// <summary>
    ///     Walk through all the non prime
    /// </summary>
    /// <param name="tableHolder"></param>
    /// <returns></returns>
    private static int WalkThroughTheNode(this int[,] tableHolder)
    {
        var tempresult = tableHolder;
        var length = tableHolder.GetLength(0);

        // walking through the non-prime node

        for (var i = length - 2; i >= 0; i--)
        {
            for (var j = 0; j < length; j++)
            {
                var c = tempresult[i, j];
                var a = tempresult[i + 1, j];
                var b = tempresult[i + 1, j + 1];
                if ((!IsPrime(c) && !IsPrime(a)) || (!IsPrime(c) && !IsPrime(b)))
                    tableHolder[i, j] = c + Math.Max(a, b);
            }
        }
        return tableHolder[0, 0];
    }

    /// <summary>
    ///     prime number check
    /// </summary>
    /// <param name="number"></param>
    /// <returns></returns>
    public static bool IsPrime(this int number)
    {
        // Test whether the parameter is a prime number.
        if (PrimeCache.ContainsKey(number))
        {
            bool value;
            PrimeCache.TryGetValue(number, out value);
            return value;
        }
        if ((number & 1) == 0)
        {
            if (number == 2)
            {
                if (!PrimeCache.ContainsKey(number)) PrimeCache.Add(number, true);
                return true;
            }
            if (!PrimeCache.ContainsKey(number)) PrimeCache.Add(number, false);
            return false;
        }

        for (var i = 3; i*i <= number; i += 2)
        {
            if (number%i == 0)
            {
                if (!PrimeCache.ContainsKey(number)) PrimeCache.Add(number, false);
                return false;
            }
        }
        var check = number != 1;
        if (!PrimeCache.ContainsKey(number)) PrimeCache.Add(number, check);
        return check;
    }
}

答案 3 :(得分:0)

我在Java中尝试了以下解决方案:

// Creating 2 dimensional array with the input triangle
int[][] data = Files.lines(Paths.get("E:\\Personal\\triangle2.txt"))
        .map(s -> stream(s.trim().split("\\s+")).mapToInt(Integer::parseInt).toArray()).toArray(int[][]::new);

int[][] originalData = Files.lines(Paths.get("E:\\Personal\\triangle2.txt"))
        .map(s -> stream(s.trim().split("\\s+")).mapToInt(Integer::parseInt).toArray()).toArray(int[][]::new);

/*
 * Below would be code flow if we didnt had to consider skipping the
 * prime numbers.
 * for (int lengthIndex = data.length - 1; lengthIndex >  0; lengthIndex--)
 *   for (int i = 0; i < data[lengthIndex].length - 1;  i++)
 *       data[lengthIndex - 1][i] += Math.max(data[lengthIndex][i],data[lengthIndex][i + 1]);
 */

// Using the bottom-up approach starting from the lowermost node to upwards
for (int lengthIndex = data.length - 1; lengthIndex > 0; lengthIndex--)
    for (int i = 0; i < data[lengthIndex].length - 1; i++) {
        System.out.println("lenghtindex is" + lengthIndex);
        if(!checkPrimeOnOriginalArray(data[lengthIndex - 1][i]) || (lengthIndex == 1)) {
            System.out.println("gettign here");
            data[lengthIndex - 1][i] += Math.max(
                    data[lengthIndex][i],data[lengthIndex][i + 1]);
            System.out.println("-->"+data[lengthIndex - 1][i]);
        }
        else {
            data[lengthIndex - 1][i] = 0;
        }
    }

//data[lengthIndex - 1][i] += Math.max(
//      checkPrimeOnOriginalArray(originalData[lengthIndex][i]) ? 0 : data[lengthIndex][i],
//      checkPrimeOnOriginalArray(originalData[lengthIndex][i + 1]) ? 0 : data[lengthIndex][i + 1]);

System.out.println("Maximum Sum Of Path Is : "+data[0][0]);

答案 4 :(得分:0)

你认为它没有检查最后一行中的素数检查并取最大值吗?

代码应如下所示:

for (int lenIndex = data.length - 1; lenIndex > 0; lenIndex--) {
        for (int i = 0; i < data[lenIndex].length - 1; i++) {
            System.out.println("---------------------");
            System.out.println("lenIndex is : " + lenIndex);
            if (!isPrimeNum(data[lenIndex - 1][i]) || (lenIndex == 1)) {
                if (lenIndex == data.length - 1) {
                    data[lenIndex - 1][i] += Math.max(isPrimeNum(data[lenIndex][i]) ? 0 : data[lenIndex][i],
                            isPrimeNum(data[lenIndex][i + 1]) ? 0 : data[lenIndex][i + 1]);

                    System.out.println("data[lenIndex][i] : " + data[lenIndex][i]+ " data[lenIndex][i + 1] :"+ data[lenIndex][i + 1]);
                    System.out.println("Number select for Sum #" + Math.max(isPrimeNum(data[lenIndex][i]) ? 0 : data[lenIndex][i],
                            isPrimeNum(data[lenIndex][i + 1]) ? 0 : data[lenIndex][i + 1]));
                } else {
                    data[lenIndex - 1][i] += Math.max(data[lenIndex][i], data[lenIndex][i + 1]);
                    System.out.println("data[lenIndex][i] : " + data[lenIndex][i]+ " data[lenIndex][i + 1] :"+ data[lenIndex][i + 1]);
                    System.out.println("Number select for Sum #" + Math.max(data[lenIndex][i], data[lenIndex][i + 1]));
                }
                System.out.println("Afrer Sum #" + data[lenIndex - 1][i]);
            } else {
                System.out.println("Prime Number - Skiping : " + data[lenIndex - 1][i]);
                data[lenIndex - 1][i] = 0;
            }
        }