【问题标题】:Finding all possible combinations of positive and negative numbers that equal a given sum找到等于给定总和的正数和负数的所有可能组合
【发布时间】:2020-03-25 05:56:06
【问题描述】:

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

关于Finding all possible combinations of numbers to reach a given sum这个话题,我无法修改它以达到我的结果,所以我决定改为询问。

示例:(假设 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

【问题讨论】:

  • 我似乎不清楚。你要找的这笔款项是多少?你是怎么计算的?您如何使用显示的数组来获得“总和”?
  • 您能否澄清关于您提供的other SO 文章链接上给出的 c# 答案的“不正确”之处?
  • 已编辑,示例中的目标是 0。@Luuk 并不是说​​有什么不正确,但我无法修改它以使其适用于正数和负数。
  • 你需要写下问题的所有规则。根据你的规则,我可以用我想要的任何数字做任何我想做的事情,给出无限的数字或可能的组合
  • @CarlosGarcia 天哪,感谢您指出这一点。我似乎没有错误地输入“+1 -1 +2 -2 +3 -3 +4 -4”,因为我正在测试一些东西。规则是我不想多次使用每个数字。编辑了问题。

标签: c# algorithm


【解决方案1】:

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

代码(测试一下here,或者更简单的版本here):

// 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 返回子树找到了多少解决方案

【讨论】:

  • 感谢您的回答,但是看来我可能弄错了,我无法很好地理解我的问题,因为您的解决方案绝对正确,但根据它并不能解决我的问题这个例子。如果我为我给出的示例运行您的代码,例如 arr = [1, 2, 3, 4, 5, 6, 7, 8], targetSum = 0;我将得到 7 个总解决方案而不是 14 个。您的代码是否检查我们在数组的第一个索引处是否有 +1 或 -1? (预先感谢)
  • @Knightwalker 不,它没有:) 这里它正在执行两棵树,一棵具有正的第一个索引,一个具有负的第一索引:dotnetfiddle.net/O4IeRd。您还可以编写更好的代码。例如,这已经更短了,它只打印成功的案例:dotnetfiddle.net/MP4U0f
  • 伙计,我非常感谢您的帮助和解释!你是对的。我希望有一天我能达到你的水平。这对你来说似乎是基本的递归函数,但对于像我这样的初学者来说,它是地狱,哈哈。
  • @Knightwalker 你会变得很好! :) 如果我的代码难以理解,这是相同的算法,但更简单(不使用对象):dotnetfiddle.net/BnBIo6
  • 控制台输出:-1 + 2 + 3 + 4 = 10 ?
【解决方案2】:

据我所知,如果我理解了这个问题,您需要一个 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

希望这会有所帮助。

【讨论】:

    【解决方案3】:

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

    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;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      • 1970-01-01
      • 2019-05-24
      • 2013-07-16
      • 1970-01-01
      相关资源
      最近更新 更多