我试图找到所有可能的值,这些值是给定数组的值之和的结果。例如,如果给定的数组是a = [50,100,120,260,360]
,那么结果将是[0,50,100,120,150,170,200,220,240,250,260,....]
。如何实现呢?
我找到了一篇文章但它即将找到使用给定数组无法形成的值。
Find smallest number which can't be formed by values of given array
我发现了另外一个与此相关的讨论,但它完全是关于数学的,我仍然无法理解如何实现它。你可以看看它 Find all possible values which can be formed using some values
C#中的任何算法或任何代码都可以提供帮助。
修改
我们可以多次使用单个值。
更多结果可能是270(50 * 1 + 100 * 1 + 120),300(100 * 3),310(50 * 1 + 260 * 1)等。
答案 0 :(得分:3)
这就是我使用的:
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: xs.Skip(1).Any()
? getAllSubsets(xs.Skip(1))
.SelectMany(ys => new[] { ys, xs.Take(1).Concat(ys) })
: new[] { Enumerable.Empty<int>(), xs.Take(1) };
然后你可以这样做:
var a = new [] { 50, 100, 120, 260, 360 };
Console.WriteLine(String.Join(", ", getAllSubsets(a).Select(x => x.Sum()).OrderBy(x => x)));
我明白了:
0,50,100,120,150,170,220,260,270,310,360,360,380,410, 410,430,460,480,480,510,530,530,580,620,630,670,720,740, 770,790,840,890
知道值可以重复,这是一种方法:
public IEnumerable<int> GenerateAllSums(int[] array)
{
var buffer = new LinkedList<int>();
buffer.AddFirst(0);
while (true)
{
var first = buffer.First;
var nexts = array.Select(a => first.Value + a);
foreach (var next in nexts)
{
var x = buffer.First;
while (x.Value < next)
{
x = x.Next;
if (x == null)
{
break;
}
}
if (x == null)
{
buffer.AddLast(next);
}
else if (x.Value != next)
{
buffer.AddBefore(x, next);
}
}
buffer.RemoveFirst();
yield return first.Value;
}
}
我可以这样称呼它:
var a = new [] { 50, 100, 120, 260, 360, };
Console.WriteLine(String.Join(", ", GenerateAllSums(a).Take(100)));
重要的是要注意.Take(...)
现在至关重要,因为序列是无限的。
鉴于.Take(100)
我得到了这个结果:
0,50,100,120,150,170,200,220,240,250,260,270,290,300, 310,320,340,350,360,370,380,390,400,410,420,430,440,450, 460,470,480,490,500,510,520,530,540,550,560,570,580,590, 600,610,620,630,640,650,660,670,680,690,700,710,720,730, 740,750,760,770,780,790,800,810,820,830,840,850,860,870, 880,890,900,910,920,930,940,950,960,970,980,990,1000, 1010,1020,1030,1040,1050,1060,1070,1080,1090,1100,1110, 1120,1130,1140,1150,1160,1170
答案 1 :(得分:1)
使用类似的东西查找数组的所有子集然后求和,如果不需要重复的数组,则将获得所有可能的值。
int[] source = new int[] { 50,100,120,260,360 };
for (int i = 0; i < Math.Pow(2, source.Length); i++)
{
int[] combination = new int[source.Length];
for (int j = 0; j < source.Length; j++)
{
if ((i & (1 << (source.Length - j - 1))) != 0)
{
combination[j] = source[j];
}
}
Console.WriteLine("[{0}, {1}, {2}]", combination[0], combination[1], combination[2]);
}
答案 2 :(得分:0)
var repeat = 8;
int[] source = new int[] {
50, 100, 120, 260, 360
};
List < int > results = new List < int > ();
for (int i = 0; i < Math.Pow(repeat, source.Length); i++) {
var sum = 0;
var bin = Convert.ToString(i, repeat);
for (var j = 0; j < bin.Length; j++) {
var pos = int.Parse(bin[j].ToString());
if (0 < pos) {
sum += source[j] * pos;
}
}
results.Add(sum);
}
Console.WriteLine(results.Union(source).Distinct().OrderBy(x = > x));
答案 3 :(得分:0)
这是最有效的方法:
public static class Algorithms
{
public static IEnumerable<int> AllSums(this int[] source)
{
var indices = new int[source.Length];
for (int count = 0, sum = 0, next = 0; ; next++)
{
if (next < source.Length)
{
indices[count++] = next;
sum += source[next];
yield return sum;
}
else
{
if (count == 0) break;
next = indices[--count];
sum -= source[next];
}
}
}
}
样本用法:
var source = new[] { 50, 100, 120, 260, 360 };
Console.WriteLine("Source: {" + string.Join(", ", source.Select(n => n.ToString())) + "}");
Console.WriteLine("Sums: {" + string.Join(", ", source.AllSums().Select(n => n.ToString())) + "}");
或
var source = new[] { 50, 100, 120, 260, 360 };
foreach (var sum in source.AllSums())
{
// do something with the sum
}