Arrays 在二维数组中查找所有可能的行和
理想情况下,我正在寻找一个c#解决方案,但算法上的任何帮助都可以 我有一个二维数组(x,y)。最大列数(max x)在2到10之间变化,但可以在实际填充阵列之前确定。最大行数(y)固定为5,但每列可以有不同数量的值,例如:Arrays 在二维数组中查找所有可能的行和,arrays,algorithm,performance,optimization,math,Arrays,Algorithm,Performance,Optimization,Math,理想情况下,我正在寻找一个c#解决方案,但算法上的任何帮助都可以 我有一个二维数组(x,y)。最大列数(max x)在2到10之间变化,但可以在实际填充阵列之前确定。最大行数(y)固定为5,但每列可以有不同数量的值,例如: 1 2 3 4 5 6 7...10 A 1 1 7 9 1 1 B 2 2 5 2 2 C 3 3 D 4 E 5 我需要计算出所有可能的行数总和,以便找到一个具体的总和。也就是说,行总计可
1 2 3 4 5 6 7...10
A 1 1 7 9 1 1
B 2 2 5 2 2
C 3 3
D 4
E 5
我需要计算出所有可能的行数总和,以便找到一个具体的总和。也就是说,行总计可以是单元格A1+B2+A3+B5+D6+A7(每列中一个值的任意组合)
这个过程将重复数百次,每次使用不同的单元格值,因此我正在寻找一个稍微优雅的解决方案(比我能够提供的更好)。谢谢您的帮助。问题的大小
我们首先考虑最坏的情况:
每列有10列和5(完整)行。应该清楚的是,你将能够得到(每个地方有适当数量的人口)最多5^10≅ 10^6不同的结果(解决方案空间)
例如,以下矩阵将给出3列的最坏情况:
| 1 10 100 |
| 2 20 200 |
| 3 30 300 |
| 4 40 400 |
| 5 50 500 |
导致5^3=125个不同的结果。每个结果的形式为{a1 a2 a3}和ai∈ {1,5}
很容易证明这样一个矩阵对于任意数量的n列总是存在的
现在,为了得到每一个数值结果,你需要做n-1个和,把问题的大小加起来就是O(n5^n)。所以,这是最糟糕的情况,我认为对此无能为力,因为要知道可能的结果,你需要有效地执行求和
更温和的化身:
可以通过两种方式消除问题的复杂性:
| 7 6 100 |
| 3 4 200 |
| 1 2 200 |
乍一看,你需要做23^3和。但事实并非如此。当您将第一列相加时,您不会得到预期的9个不同结果,而只有6个({13,11,9,7,5,3})。所以你不必把你的九个结果带到第三列,只需要6个 当然,这是以从列表中删除重复编号为代价的。“删除重复的整数元素”,我不在这里重复讨论,只引用在列表大小(m)中执行mergesort O(m log m)将删除重复项。如果您想要更简单的东西,可以使用双循环O(m^2) 无论如何,出于几个原因,我不会用这种方法计算(平均)问题的大小。其中之一是排序合并中的“m”不是问题的大小,而是将任意两列相加后结果向量的大小,并且该操作重复(n-1)次。。。我真的不想做数学:(。 另一个原因是,当我实现该算法时,我们将能够使用一些实验结果,从而避免我的理论考虑 算法 根据我们之前所说的,显然我们应该针对良性病例进行优化,因为最坏的病例是丢失的。
为此,我们需要对列使用列表(或变量dim向量,或任何可以模拟这些的东西),并在每个列添加后进行合并。
在不修改结果的情况下,可以用其他几种算法(例如在BTree上插入)替换合并 因此,算法(过程伪代码)类似于:
Set result_vector to Column 1
For column i in (2 to n-1)
Remove repeated integers in the result_vector
Add every element of result_vector to every element of column i+1
giving a new result vector
Next column
Remove repeated integers in the result_vector
或者,按照您的要求,递归版本的工作方式如下:
function genResVector(a:list, b:list): returns list
local c:list
{
Set c = CartesianProduct (a x b)
Set c = Sum up each element {a[i],b[j]} of c </code>
Drop repeated elements of c
Return(c)
}
function ResursiveAdd(a:matrix, i integer): returns list
{
genResVector[Column i from a, RecursiveAdd[a, i-1]];
}
function ResursiveAdd(a:matrix, i==0 integer): returns list={0}
算法实现(递归)
我选择函数式语言,我想把它翻译成任何过程式语言都没什么大不了的
我们的程序有两个功能:
genResVector[x__, y__] := (* Header: A function that takes two lists as input *)
Union[ (* remove duplicates from resulting list *)
Apply (* distribute the following function on the lists *)
[Plus, (* "Add" is the function to be distributed *)
Tuples[{x, y}],2] (*generate all combinations of the two lists *)];
recursiveAdd[t_, i_] := genResVector[t[[i]], recursiveAdd[t, i - 1]];
(* Recursive add function *)
recursiveAdd[t_, 0] := {0}; (* With its stop pit *)
试验
如果我们以你的清单为例
| 1 1 7 9 1 1 |
| 2 2 5 2 2 |
| 3 3 |
| 4 |
| 5 |
然后运行程序,结果是:
{11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}
最大值和最小值很容易验证,因为它们对应于从每个列中获取最小值或最大值
一些有趣的结果
让我们考虑当矩阵的每个位置上的数有界时会发生什么。对于这个,我们将取一个完整的(10×5)矩阵,并用随机整数填充它。 在整数仅为0或1的极端情况下,我们可以预期两件事:
实验1:5x10矩阵填充不同范围的随机整数 很明显,对于接近最大结果集大小(5^10)的结果集≅ 10^6)计算时间和“结果数”有一个渐近线。我们看到函数增加的事实表明我们离那个点还很远 士气:你的元素越小,你越有可能快速获得它。这是因为你可能有很多重复 请注意,对于测试的最坏情况,我们的最大计算时间接近20秒
实验2:不可用的优化 有了大量可用的内存,我们可以用蛮力计算,而不需要删除重复的结果 结果很有趣…10.6秒!…等等!发生了什么事?我们的“删除重复整数”小把戏占用了很多时间,当没有太多的结果要删除时,没有任何好处,但在尝试消除重复时会有所松动 但我们可能会得到很多好处