我已经实现了一种算法,该算法在Y框中写出X项的所有可能组合(在组合学中,我相信它们被称为组合)。我使用递归函数编写了这个算法,因为它更容易跟踪我们将项目放入的当前框以及剩余的项目数。 该算法给出了以下输出(4个盒子和3个项目):
[3,0,0,0],[2,1,0,0],[2,0,1,0],[2,0,0,1],[1,2,0, 0],[1,1,1,0],......,[0,0,1,2],[0,0,0,3]
你可以想象,对于大X和Y,组合的数量会增长很多。由于我不关心订单组合的进展,我想要进一步计算,但我可以&#39 ; t在递归函数上执行此操作(我已尝试通过保存递归状态来执行此操作,但这非常混乱,尽管它有效,但它确实很慢) 。
所以,我想知道是否可以迭代地重新编写相同的函数(使用for
循环),以便我可以并行化它。 (需要记住的一点是,优化也很重要,因为我需要为大X和Y运行函数)我的递归函数如下所示:
public void charArrangements (int boxes, int items, String strBuild) {
if (boxes > 1) {
for (int i = 0; i <= items; i++) {
String ss = strBuild + (items - i) + ";";
charArrangements(boxes - 1, i, ss);
}
}
else {
String ss = strBuild + items;
List<Integer> charArrangement = new ArrayList<Integer>();
charArrangement = Stream.of(ss.split(";")).map(Integer::parseInt).collect(Collectors.toList());
doCalculations(charArrangement);
}
}
答案 0 :(得分:1)
有线程就像
public void charArrangements (int boxes, int balls, String strBuild) {
ArrayList<myThread> arr=new ArrayList<>();//fill arraylist
for(int j=boxes;j>1;j--){
arr.get(j).start();
}
}
//put this login in your threads run() method
public void someFunc(int balls, String strBuild)
{
for (int i = 0; i <= balls; i++) {
String ss = strBuild + (balls - i) + ";";
}
}
答案 1 :(得分:0)
我认为你需要这个。让我们试试
public void charArrangements (int boxes, int balls, String strBuild) {
for(int j=boxes;j>1;j--){
for (int i = 0; i <= balls; i++) {
String ss = strBuild + (balls - i) + ";";
}
}
}
在此之后你可以做你在else子句中的逻辑。
答案 2 :(得分:0)
您可以在不同的线程和join
当前线程中调用递归调用,例如:
public void charArrangements (int boxes, int balls, String strBuild) {
if (boxes > 1) {
for (int i = 0; i <= balls; i++) {
String ss = strBuild + (balls - i) + ";";
final int count = i;
try{
Runnable r = new Runnable() {
@Override
public void run() {
charArrangements(boxes - 1, count, ss);
}
};
Thread t = new Thread(r);
t.start();
t.join();
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
else {
String ss = strBuild + balls;
List<Integer> charArrangement = new ArrayList<Integer>();
charArrangement = Stream.of(ss.split(";")).map(Integer::parseInt).collect(Collectors.toList());
}
}
P.S。删除了文件写入部分。
答案 3 :(得分:0)
为什么不能并行化递归函数?使用主线程来完成前N个级别(最好的N取决于你的问题空间),然后让并发工作者处理级别N + 1及以后。
答案 4 :(得分:0)
听起来您希望能够更直接地访问累积解决方案的状态;例如,能够保存和恢复它,而不必每次都重建它。实现此目的的一种方法是使用词典生成。
我建议首先创建没有任何零的数字分区,然后添加零并使用已知的简单算法进行下一个词典排列,您可以在线轻松查找。以下是将5个项目分为7个框的示例:
Order partitions in decreasing order by number of parts
[0,0,1,1,1,1,1] -> generate all lexicographic permutations
[0,0,0,1,1,1,2] -> generate all lexicographic permutations
[0,0,0,0,1,2,2] -> ...
以下是我提出的用于相反大小的相反下一个词典分区的算法,也许它可以改进或纠正(我们将其反转,以便我们可以从下一步中排名最低的排列开始):
(0) The first partition is either k (n/k)'s if k divides n,
or (remainder of n/k) (n/k + 1)'s and (k - remainder of n/k)'s (n/k)'s
to their left.
(1) Find the leftmost part, l, greater than 1
(2) If l is the rightmost part, we're done.
Otherwise, decrement l and increment the leftmost part, r,
right of l that is lower than its right neighbour.
If r is not found, increment the rightmost part and
set the rest of the partition according to
instruction (0), where k and n now would be
(k - 1) and (n - rightmost part), respectively.
[0,0,0,0,1,2,2] -> generate all lexicographic permutations
[0,0,0,0,1,1,3] -> ...
etc.
答案 5 :(得分:0)
一个简单但丑陋的迭代算法,用于以反向词典顺序枚举弱k组合,可能如下所示:
static void weakCompositions(int n, int k, Consumer<int[]> callback) {
assert n >= 0: n;
assert k >= 0: k;
if (k == 0)
return;
int C[], i, x;
C = new int[k];
C[0] = n;
while (true) {
callback.accept(C);
i = k - 2;
while (i >= 0 && C[i] == 0)
i--;
if (i < 0)
break;
C[i]--;
x = C[k - 1] + 1;
C[k - 1] = 0;
C[i + 1] = x;
}
}
其中n
是项目数,k
是方框数。
不确定它是否适合并行化。
基本思想是在数组的前缀中找到最右边的非零值的位置(即,排除最后的条目);将“转移”1从该位置转移到其右边;并且,进入那个新位置,将所有值吸收到它的右边(如果有任何值,它应该只是数组中的最后一个值,通过构造)。
我认为应该可以跟踪数组前缀的最右边非零值,而不必为生成的每个组合扫描它。这样做也可以更容易地分析算法并查看它是否是恒定的摊销时间。
最后,number of weak k-compositions由(n + k - 1)! / n! / (k - 1)!
提供。你提到你最后的问题空间是75个盒子中的11个项目,超过21万亿个对象!即使使用并行化,这似乎是......难以理解的。祝你好运!