繁体   English   中英

查找等于给定总和的所有可能的正数和负数组合

[英]Finding all possible combinations of positive and negative numbers that equal a given sum

如果你想看看有多少种方法可以组合从 1 到 N 的数字,通过使用加法或减法,你最终会得到等于给定目标数字的组合,你会怎么做。

关于这个主题找到所有可能的数字组合以达到给定的总和,我无法以能够实现我的结果的方式修改它,所以我决定改为询问。

示例:(假设 N = 8。如果我创建以下从 1 到 N 的数组,我将如何解决这个问题。不要多次使用每个数字。)

  • arr = [1, 2, 3, 4, 5, 6, 7, 8]
  • 总和 = 0;

结果:

  • +1 +2 +3 +4 -5 -6 -7 +8
  • +1 +2 +3 -4 +5 -6 +7 -8
  • +1 +2 -3 +4 +5 +6 -7 -8
  • +1 +2 -3 -4 -5 -6 +7 +8
  • +1 -2 +3 -4 -5 +6 -7 +8
  • +1 -2 -3 +4 +5 -6 -7 +8
  • +1 -2 -3 +4 -5 +6 +7 -8
  • -1 +2 +3 -4 +5 -6 -7 +8
  • -1 +2 +3 -4 -5 +6 +7 -8
  • -1 +2 -3 +4 +5 -6 +7 -8
  • -1 -2 +3 +4 +5 +6 -7 -8
  • -1 -2 +3 -4 -5 -6 +7 +8
  • -1 -2 -3 +4 -5 +6 -7 +8
  • -1 -2 -3 -4 +5 +6 +7 -8
  • 总解决方案:14

这里是一个递归函数,它将打印所有有效的组合,以及那些无效的组合。

代码(测试它在这里,或简单的版本在这里):

// This code can be improved a lot, but i wrote it in the way that i believe it is easier to read and understand what it does.

using System;

namespace algorithm_simple_csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Working on it!");

            int[] allNumbers = new int[] {1,2,3,4};
            int desiredSum = 0;

            // We will create two trees, one with a positive first number, and the other one with a negative one

            // Positive tree
            int initIndex = 0;
            OperationTreeNode firstPositiveNode = new OperationTreeNode
            {
                parentNode = null,
                currentNumber = allNumbers[initIndex],
                accumulativeSum = allNumbers[initIndex],
                operation = "+"
            };

            int totalSolutionsPositiveFirst = ApplyNumber(firstPositiveNode, allNumbers, initIndex + 1, desiredSum);

            // Negative tree
            OperationTreeNode firstNegativeNode = new OperationTreeNode
            {
                parentNode = null,
                currentNumber = -allNumbers[initIndex],
                accumulativeSum = -allNumbers[initIndex],
                operation = "-"
            };

            int totalSolutionsNegativeFirst = ApplyNumber(firstNegativeNode, allNumbers, initIndex + 1, desiredSum);

            // Print all solutions found with both trees
            Console.WriteLine("Total soltions: " + (totalSolutionsPositiveFirst + totalSolutionsNegativeFirst));
        }


        // This function will take care of the next number we should apply: allNumbers[index]
        // If there are still numbers to apply, It will create two nodes, one for + allNumbers[index] and one for - allNumbers[index]
        static int ApplyNumber(OperationTreeNode currentNode, int[] allNumbers, int index, int desiredSum)
        {

            // The base case, There are no more numbers to cover.
            // In that case we evaluate if the last node is equal to desiredSum or not
            if(index > allNumbers.GetUpperBound(0))
            {
                if(currentNode.accumulativeSum == desiredSum)
                {
                    Console.WriteLine(currentNode.BranchToString() + " = " + currentNode.accumulativeSum + "  <---   THIS ONE");
                    return 1;
                }

                Console.WriteLine(currentNode.BranchToString() + " = " + currentNode.accumulativeSum);
                return 0;
            }

            // If it is not the last node, then we create two child nodes of the current node.
            // First we evaluate what happens if we apply a + to the next number...
            OperationTreeNode plusNode = new OperationTreeNode
            {
                parentNode = currentNode,
                currentNumber = allNumbers[index],
                accumulativeSum = currentNode.accumulativeSum + allNumbers[index],
                operation = "+"
            };
            int totalSolutionsWithPlus = ApplyNumber(plusNode, allNumbers, index +1, desiredSum);

            // Now we evaluate what happens if we apply a - to the next number...
            OperationTreeNode minusNode = new OperationTreeNode
            {
                parentNode = currentNode,
                currentNumber = allNumbers[index],
                accumulativeSum = currentNode.accumulativeSum - allNumbers[index],
                operation = "-"
            };
            int totalSolutionsWithMinus = ApplyNumber(minusNode, allNumbers, index +1, desiredSum);

            // The total number of solutions we found is the sum of the solutions of both sub-trees
            return totalSolutionsWithPlus + totalSolutionsWithMinus;
        }

    }


    public class OperationTreeNode
    {
        public int accumulativeSum = 0;
        public OperationTreeNode parentNode = null;
        public int currentNumber = 0;
        public string operation;

        public string BranchToString()
        {
            if(parentNode == null)
            {
                return $"{this.currentNumber} ";
            }

            return $"{parentNode.BranchToString()} {this.operation} {this.currentNumber} ";
        }
    }
}

控制台中的输出

Working on it!
1  + 2  + 3  + 4  = 10
1  + 2  + 3  - 4  = 2
1  + 2  - 3  + 4  = 4
1  + 2  - 3  - 4  = -4
1  - 2  + 3  + 4  = 6
1  - 2  + 3  - 4  = -2
1  - 2  - 3  + 4  = 0  <---   THIS ONE
1  - 2  - 3  - 4  = -8
-1  + 2  + 3  + 4  = 8
-1  + 2  + 3  - 4  = 0  <---   THIS ONE
-1  + 2  - 3  + 4  = 2
-1  + 2  - 3  - 4  = -6
-1  - 2  + 3  + 4  = 4
-1  - 2  + 3  - 4  = -4
-1  - 2  - 3  + 4  = -2
-1  - 2  - 3  - 4  = -10
Total soltions: 2

这个怎么运作?

它创建了一棵树。 树的每个节点都是一个OperationTreeNode类型的对象,表示一个数字及其操作。 例如:+1 和 -1 是两个OperationTreeNode

当您达到最后一个数字时, ApplyNumber将评估节点是否等于desiredSum

ApplyNumber返回子树找到的ApplyNumber

据我所知,如果我理解了这个问题,你需要一个for循环,因为如果你有一个数字n ,那么加或减的数字有无限组合等于n ,所以你需要一个数字,如果达到将停止该过程。 如果您需要多个数字(例如 3+10+1=14),您需要更多的循环。 这将是我要走的路:

int l = 50;//my limit
int n = 14;//my number
for(int i = 0; i < l; i++) 
        {
           for(int j = 0; j < l; j++) 
           {
                if ( i + j == n ) 
                {
                //Do whatever you want
                        Console.WriteLine("{0} = {1} + {2}", n, i, j);
                }
                if ( i - j == n ) 
                {
                //Do whatever you want
                       Console.WriteLine("{0} = {1} - {2}", n, i, j);
                }
         }
      }//Repeat for negative numbers

希望这会有所帮助。

迭代,有多少种方法可以达到一个目标。

using System;
class Program
{
    static void Main()
    {
        Console.WriteLine(C(0));
        int[] a = { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144 };
        Console.Write(C(0, a)); Console.Read();
    }

    static int C(int t)  // ±1 ± 2 ± 3 ± 4 == 0
    {
        int c = 0, s = 0;
        for (int n = 0; n < 16; n++)
        {
            if ((n & 1) == 0) s -= 1; else s += 1;
            if ((n & 2) == 0) s -= 2; else s += 2;
            if ((n & 4) == 0) s -= 3; else s += 3;
            if ((n & 8) == 0) s -= 4; else s += 4;
            if (s == t) c++; s = 0;
        } return c;
    }

    static int C(int t, int[] a)
    {
        int c = 0, s = 0, i, j = a.Length, n, m = 1 << j;
        for (n = 0; n < m; n++)
        {
            for (i = 0; i < j; i++)
                if ((n & 1 << i) == 0) s -= a[i]; else s += a[i];
            if (s == t) c++; s = 0;
        } return c;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM