C# 在一组数中求和等于已知数的组合的有效算法

C# 在一组数中求和等于已知数的组合的有效算法,c#,C#,假设有一组数字 1,2,3,4,5,6,7,8,9,10 我想找出数集合中的几个组合,使之和等于一个已知数,例如,18。我们可以发现5,6,7是匹配的(5+6+7=18) 组合中的数字不能重复,集合中的数字可能不连续 我写了一个C#程序来实现这一点。该程序是随机的,用于提取数字以形成组合,并检查组合的总和是否等于已知数字。然而,该计划发现的组合可能会重复,从而使进展无效 我想知道是否有任何有效的算法来找出这种组合 这是我的部分代码 int Sum = 0; int

假设有一组数字

1,2,3,4,5,6,7,8,9,10

我想找出数集合中的几个组合,使之和等于一个已知数,例如,18。我们可以发现5,6,7是匹配的(5+6+7=18)

组合中的数字不能重复,集合中的数字可能不连续

我写了一个C#程序来实现这一点。该程序是随机的,用于提取数字以形成组合,并检查组合的总和是否等于已知数字。然而,该计划发现的组合可能会重复,从而使进展无效

我想知道是否有任何有效的算法来找出这种组合

这是我的部分代码

        int Sum = 0;
        int c;
        List<int> Pick = new List<int>();
        List<int> Target = new List<int>() {some numbers}

        Target.Sort();

            while (!Target.Contains(Sum))
            {
                if (Sum > Target[Target.Count - 1])
                {
                            Pick.Clear();
                            Sum = 0;

                }
                while (true)
                {
                    if (Pick.IndexOf(c = Math0.rand(0, Set.Count - 1)) == -1)
                    {
                        Pick.Add(c);
                    }

                    //Summation Pick
                    Sum = 0;
                    for (int i = 0; i < Pick.Count; i++)
                        Sum += Set[Pick[i]];

                    if (Sum >= Target[Target.Count - 1])
                        break;
                }


            }

            Result.Add(Pick);
int和=0;
INTC;
列表选择=新列表();
List Target=new List(){some number}
Target.Sort();
而(!Target.Contains(Sum))
{
如果(总和>目标[Target.Count-1])
{
Pick.Clear();
总和=0;
}
while(true)
{
if(Pick.IndexOf(c=Math0.rand(0,Set.Count-1))=-1)
{
选择。添加(c);
}
//总和选择
总和=0;
for(int i=0;i=Target[Target.Count-1])
打破
}
}
结果。添加(拾取);

您可以使用递归。对于集合中的任何给定数字,找出与该数字相加的较小数字的组合:

public static IEnumerable<string> GetCombinations(int[] set, int sum, string values) {
  for (int i = 0; i < set.Length; i++) {
    int left = sum - set[i];
    string vals = set[i] + "," + values;
    if (left == 0) {
      yield return vals;
    } else {
      int[] possible = set.Take(i).Where(n => n <= sum).ToArray();
      if (possible.Length > 0) {
        foreach (string s in GetCombinations(possible, left, vals)) {
          yield return s;
        }
      }
    }
  }
}
输出:

1,2,4,5,6,
3,4,5,6,
1,2,3,5,7,
2,4,5,7,
2,3,6,7,
1,4,6,7,
5,6,7,
1,2,3,4,8,
2,3,5,8,
1,4,5,8,
1,3,6,8,
4,6,8,
1,2,7,8,
3,7,8,
2,3,4,9,
1,3,5,9,
4,5,9,
1,2,6,9,
3,6,9,
2,7,9,
1,8,9,
1,3,4,10,
1,2,5,10,
3,5,10,
2,6,10,
1,7,10,
8,10,

一种可能的替代方法。像这样的一个小集合,你可以使用蛮力。您的集合
{1,2,3,4,5,6,7,8,9,10}
有10个元素,每个元素可以存在也可以不存在。可以映射到0(=0b0000000000)和1023(=0B1111111)之间的二进制数。循环遍历从0到1023(含0到1023)的数字,并检查与该数字二进制表示的设定位对应的子集的和


对于这个问题,也许不是最有用的,但是生成给定集合的所有可能子集的好方法。

这是子集和问题:这是本周早些时候提出的问题。如何修改此解决方案以获得重复数的可能重复,例如:
5,5,3
2,2,2,2,2,2,2,2,2,2
?@kelumpriyadarshane,而不是初始化并传递
int[]可能的
只需在递归调用中传递
设置
即可。应该
n请解释一下1023。你如何找到1023高度数字来检查?问题中有十个数字:1,2,3。。。10这十个数字中的每一个都可以包含在结果(1)中,也可以从结果(0)中排除。使用0000000000表示排除的所有数字,使用1111111表示包含的所有数字。其他可能的结果介于这两者之间,如:1001010011。现在将所有可能的结果表示为二进制数。0b0000000000=0和0b1111111111=1023。这就是1023的来源:(2^10)-1。对于要检查的12个数字的问题,请使用(2^12)-1=4095
1,2,4,5,6,
3,4,5,6,
1,2,3,5,7,
2,4,5,7,
2,3,6,7,
1,4,6,7,
5,6,7,
1,2,3,4,8,
2,3,5,8,
1,4,5,8,
1,3,6,8,
4,6,8,
1,2,7,8,
3,7,8,
2,3,4,9,
1,3,5,9,
4,5,9,
1,2,6,9,
3,6,9,
2,7,9,
1,8,9,
1,3,4,10,
1,2,5,10,
3,5,10,
2,6,10,
1,7,10,
8,10,