一旦列出了网格中所有(可能重叠的)T形的列表,剩下的就是最大的包装问题。
通常,这是一个NP完全问题。但是,您的网格足够小(通常分解为更小的独立子问题),因此很可能可以获取精确的解决方案。
附录:这是一个基本的回溯搜索算法,可以解决这个问题:
function max_packing_recursive ( set A, set S, set M ):
if |M| < |S| then let M = S;
for each shape X in A do:
remove X from A;
let B = A;
remove all shapes that intersect with X from B;
if |M| < |B| + |S| + 1 then: // upper bound
let M = max_packing_recursive( B, S + {X}, M );
end if
if |M| >= |A| + |S| then return M; // shortcut
end for
return M;
end function
function max_packing( set A ):
return max_packing_recursive( A, {}, {} );
end function
这里,{X, Y, Z}表示包含的元素的集合X,Y和Z(与{}是空集),并且|Q|表示所述集合的大小Q。
在递归函数中,集合A包含可用于其余解S的形状,包含当前解候选中的形状,并且M是迄今为止的最大解(您可能希望将其存储为全局变量,而不是将其返回到呼叫链)。重要的优化是在标记为的行上进行// upper bound,该操作会修剪搜索树的分支,这些分支可能无法返回比更好的解决方案M。
(实际上,由于我们知道每个T形都恰好包含四个位点,因此,用|B|,中的形状B除以4并四舍五入的不同位点的数量代替,可以获得更好的上限|A|。标有// shortcut)的行。但是,上述算法可用于任意形状的集合。)
我上面没有实现的一种可能的其他优化方法是,在递归函数的开头检查是否A分为多个独立的子集,即不同子集中没有形状重叠的意义,如果是,则应用将算法分别应用于每个子集。(无论如何,您肯定希望在调用递归算法之前在顶层至少执行一次此操作。)在对形状A进行循环之前对其进行适当排序(例如,按重叠形状的数量增加顺序)也可能会有所帮助。