想象一下,我们有一些袋子的种子,每个袋子包含不同种类的树。这些袋子按从高到低的顺序排列。
E.g. bag = { 1, 2, 3, 4, 5 }, bag[i] = seed quantity; species of bag[0] taller then species of bag[1];
我被要求计算所有可能满足3种条件的所有种子的种植方式:
E.g. With the bag = { 2, 2 }, these are 8 ways to plant.
Define species of bag[0] is 2, bag[1] is 1:
2 2 1 1
2 2 1
1
2 1
2 1
2 2
1
1
2
2
1
1
2 1
2
1
2 1 1
2
2 2
1 1
我认为这是排列计数问题,对吗?
我尝试了一种递归方法来解决该问题:
int PlantTree(int[] bag)
{
if (bag.Length < 1) return 0;
// Initialize top row
var top = new int[bag.Sum()];
// Get the first seed
var fs = 0;
for (; fs < bag.Length; fs++)
if (bag[fs] > 0) break;
bag[fs]--;
var ret = 0;
for (var i = 1; i <= bag.Sum() + 1; i++)
{
PlantRow(bag, top, 0, 1, i, ref ret);
}
return ret;
}
void PlantRow(int[] bag, int[] top, int sIdx, int rIdx, int rLen, ref int count)
{
var sum = bag.Sum();
if (sum == 0)
{
count++;
return;
}
if (rIdx == rLen)
{
var fs = 0;
for (; fs < bag.Length; fs++)
if (bag[fs] > 0) break;
bag[fs]--;
// Plant next row
var len = sum < rLen ? sum : rLen;
for (var i = 1; i <= len; i++)
{
PlantRow(bag, top, 0, 1, i, ref count);
}
bag[fs]++;
return;
}
for (; sIdx < bag.Length; sIdx++)
{
if (bag[sIdx] <= 0) continue;
if (top[rIdx] > sIdx)
{
sIdx = top[rIdx] - 1;
continue;
}
// Place seed into top
var sTop = top[rIdx];
top[rIdx] = sIdx;
bag[sIdx]--;
PlantRow(bag, top, sIdx, rIdx + 1, rLen, ref count);
bag[sIdx]++;
top[rIdx] = sTop;
}
}
我的代码仅需少量种子即可正常工作,例如bag = {4,4,4,4,4}。
但是对于更大的集合,例如bag = {8,8,8,8,8},它的运行时间非常长(几小时,甚至几天)。
我的递归方法有什么错误吗? 还是有另一种方法可以解决此排列计数问题?
非常感谢