我有这段代码:
ArrayList arrayA = new ArrayList();
ArrayList arrayB = new ArrayList();
ArrayList arrayC = new ArrayList();
ArrayList arrayD = new ArrayList();
ArrayList arrayE = new ArrayList();
ArrayList arrayF = new ArrayList();
ArrayList arrayG = new ArrayList();
ArrayList arrayH = new ArrayList();
ArrayList arrayI = new ArrayList();
ArrayList arrayJ = new ArrayList();
int n = 0;
for (decimal a = 0.1m; a <= 100m; a += 0.1m)
{
for (decimal b = 100m - a; b > 0m; b -= 0.1m)
{
for (decimal c = 100m - b; c > 0m; c -= 0.1m)
{
for (decimal d = 100m - c; d > 0m; d -= 0.1m)
{
for (decimal e = 100m - d; e > 0m; e -= 0.1m)
{
for (decimal f = 100m - e; f > 0m; f -= 0.1m)
{
for (decimal g = 100m - f; g > 0m; g -= 0.1m)
{
for (decimal h = 100m - g; h > 0m; h -= 0.1m)
{
for (decimal i = 100m - h; i > 0m; i -= 0.1m)
{
for (decimal j = 100m - i; j > 0m; j -= 0.1m)
{
if ((a + b + c + d + e + f + g + h + i + j) == 100)
{
++n;
arrayA.Add(a);
arrayB.Add(b);
arrayC.Add(c);
arrayD.Add(d);
arrayE.Add(e);
arrayF.Add(f);
arrayG.Add(g);
arrayH.Add(h);
arrayI.Add(i);
arrayJ.Add(j);
}
}
}
}
}
}
}
}
}
}
}
任何想法如何优化这个?这将永远执行。
基本上所需要的是知道10和0.1之间的数字的组合数,其中它们的总和恰好为100.(我需要知道组合的数量和组合本身)
提前致谢
答案 0 :(得分:3)
我不认为这个问题有一个直接的解决方案,特别是对于这种类型的数字。但是,这是一个非常一般的想法,可以帮助您开发自己的算法:
我知道这不是一件容易的事,我不想自己实现。但它会给你一个O(n)时间复杂度,你只需在线性时间内迭代组合,使用该位序列在步骤0.1中选择0.1到100之间的数字并检查它们的和是否为100.并添加位序列到最后的ArrayList。
在Ronan Thibaudau的警告之后编辑:我很抱歉我直接跳到了Java,但我认为你可以用你喜欢的语言/框架找到相应的方法。
另一个编辑:现在帖子与语言无关。想法完全一样......我所说的只是;如果您正在考虑使用大型组合这样的问题,这个想法可以为您提供O(n)时间复杂度和O(n)内存要求。这实际上保证了它将在可行的时间内运行,在任何足够大的n下消耗可行的内存量。
自编辑:我仍然在考虑这个问题并且必须进行更正。 (我保留了一些错误的算法分析)
Gosper的Hack肯定会给你O(n)时间复杂度来生成组合,这对于获得可接受的优化实现至关重要。但是,由于您必须创建自己的类来表示位序列,因此必须实现自己的移位器,加法器和诸如此类的东西(即,您无法直接将硬件用于这些操作)。为此,您将需要另一个n循环。 这可能会使您的算法复杂度为O(n 2 )
它绝对不如O(n),但仍应满足您的执行时间要求。
答案 1 :(得分:2)
如果你真的想优化提出的算法,我首先要省略不必要的循环,如果总和> = 100则继续有意义,例如:
for (decimal a = 0.1m; a <= 100m; a += 0.1m)
{
for (decimal b = 100m - a; b > 0m; b -= 0.1m)
{
if (a + b >= 100m)
continue;
for (decimal c = 100m - b; c > 0m; c -= 0.1m)
{
if (a + b + c >= 100m)
continue;
...
无论如何,您永远无法存储所有组合。例如,如果您只有三个数字,则输出将包含1000 ^ 2个结果。您可以任意选择的第一个数字(0.1 ... 100,因此您有1000个选择),与第二个相同,例如,我选择0.5和42 - 我修复的第三个,57.5 - 所以它& #39; s 1000 * 1000 * 1效果不错。现在将其扩展为10个数字。
答案 2 :(得分:2)
我认为这是使用LINQ执行此操作的最佳方法:
var n = 1000;
var query =
from a in Enumerable.Range(1, n)
from b in Enumerable.Range(1, n - a)
from c in Enumerable.Range(1, n - a - b)
from d in Enumerable.Range(1, n - a - b - c)
from e in Enumerable.Range(1, n - a - b - c - d)
from f in Enumerable.Range(1, n - a - b - c - d - e)
from g in Enumerable.Range(1, n - a - b - c - d - e - f)
from h in Enumerable.Range(1, n - a - b - c - d - e - f - g)
from i in Enumerable.Range(1, n - a - b - c - d - e - f - g - h)
let j = n - a - b - c - d - e - f - g - h - i
where j >= 1
select new { a, b, c, d, e, f, g, h, i, j };
我选择使用int
并将数字乘以10
而不是decimal
增加0.1
。
现在用1000运行它似乎需要永远。
所以我开始使用较小的数字运行它并获得这些结果:
10 1
11 10
12 55
13 220
14 715
15 2002
16 5005
17 11440
18 24310
19 48620
20 92378
n
&amp;返回的组合数量。
事实证明,这种进展是C(n - 1, n - 10)
。所以插入n = 1000
我得到2,634,095,604,619,700,000,000组合。
现在,如果我使用n = 30
运行,在我的计算机上计算10,015,005组合需要11.551秒。
如果你对此进行数学计算,假设每年有365.25天,那么你想出了为n = 1000
计算需要96,271,110年的数字。
Even&#34; Deep Thought&#34;计算更快42.好运等待它。
答案 3 :(得分:1)
这里是一个答案(为了简单起见,从1到1000而不是0.1到100,只需将所有项目除以10即可得到0.1到100之间的值)
首先,我们将使用生成器枚举和惰性运算符来避免内存问题,所有内容都会被1流式传输到管道中,因此在代码运行时应该修复内存
var kitems = Enumerable.Range(1,1000);
var q = from a in kitems
from b in kitems
from c in kitems
from d in kitems
from e in kitems
from f in kitems
from g in kitems
from h in kitems
from i in kitems
from j in kitems
where a+b+c+d+e+f+g+h+i+j == 1000
select new {a,b,c,d,e,f,g,h,i,j};
// Since everything is lazy evaluated, the 10 first results are near immediate (nothing past those is evaluate, this is good for testing, remove the take operator if you want the full dataset)
foreach(var item in q.Take(10))
{
// Do whatever you want with the result here
}
答案 4 :(得分:1)
让我们推理整数(1到1000,总和1000)。令C(K,N)为涉及总共N的K个变量的组合的数量。
对于单个变量,我们有1种可能性(a = 1000),即C(1,1000)= 1。更一般地,C(1,N)= 1。
有两个变量,我们有999个组合(a = 1,b = 999到a = 999,b = 1),我们看到C(2,1000)= C(1,999)+ C(1, 998)+ C(1,997)+ ... C(1,1)。更一般地,C(2,N)= N-1。
有三个变量,我们有C(2,999)组合,a = 1,C(2,998),a = 2 ...和C(2,2),a = 998。通过三角数的公式,C(3,N)= N.(N-1)/ 2。
对于四个变量,我们有C(3,999)组合,a = 1,C(3,998),a = 2 ...和C(3,3),a = 997。通过四面体数C(4,N)= N.(N-1)。(N-2)/ 6的公式。
等等(这只是Pascal的三角形),直到:
C(10,N)= N.(N-1)。(N-2)。(N-3)。(N-4)。(N-4)。(N-6)。(N -7)。(N-8)。(N-9)/ 9!
C(10,1000)= 2634095604619702128324000
没有希望通过枚举来计算这个天文数字!