我遇到了有关组合学的问题。不幸的是,我无法抽象地描述它,所以我试着把它解释为一个故事。 :)
问题:
简单易行:
所有100名儿童并排站立。您只需决定将它们分组到哪里并找到所有解决方案。
示例(值是高度):
[120 ... 190 ... 199] ... [126 ... 137 ... 144 ... 188] 是不可能的
[101] ... [104 ... 105 ... 112 ... 149] ... [169 ... 189] 是可能的
我希望你能帮助我。非常感谢你提前!
PS:这不是功课。 ;)通常,我需要一个用数字执行此操作的函数。但我无法将其描述为“在所有数字排序时构建k组数字”。我以为你不会这样理解。 :) PHP中的解决方案是最好的,但我很高兴看到其他语言的解决方案。 :)答案 0 :(得分:4)
据我所知,你实际上是在想方法将区间[100,199]分成10个部分,即你想找到数字x [0],...,x [10],这样:
x[0] = 100 < x[1] < x[2] < ... < x[9] < x[10] = 199
定义一个递归函数partition(intervalSize, pieces)
,它计算分区给定间隔的方法数。你在partition(100, 10)
之后。
以下Java代码对分区进行计数(抱歉,不熟悉PHP):
public class Partitions
{
static long[][] partitions = new long[100][10];
private static long partition(int intervalSize, int pieces)
{
if (partitions[intervalSize-1][pieces-1] != 0) {
return partitions[intervalSize-1][pieces-1];
}
long partition = 0L;
if (pieces == 1) {
partition = 1L;
} else {
for (int i = 1; i <= intervalSize - 1; i++) {
partition += partition(intervalSize - i, pieces - 1);
}
}
partitions[intervalSize-1][pieces-1] = partition;
return partition;
}
public static void main(String[] args)
{
System.out.println(partition(100, 10));
}
}
以下Java代码打印出实际分区。因为(100,10)的分区数量很高,我正在解释(5,3)的答案:
public class Partitions2
{
private static void showPartitions(int sizeSet, int numPartitions)
{
showPartitions("", 0, sizeSet, numPartitions);
}
private static void showPartitions(String prefix, int start, int finish,
int numLeft)
{
if (numLeft == 0 && start == finish) {
System.out.println(prefix);
} else {
prefix += "|";
for (int i = start + 1; i <= finish; i++) {
prefix += i + ",";
showPartitions(prefix, i, finish, numLeft - 1);
}
}
}
public static void main(String[] args)
{
showPartitions(5, 3);
}
}
输出结果为:
|1,|2,|3,4,5, |1,|2,3,|4,5, |1,|2,3,4,|5, |1,2,|3,|4,5, |1,2,|3,4,|5, |1,2,3,|4,|5,
答案 1 :(得分:0)
我需要所有可能的解决方案 这些团体既然不难 找到一个星座。
通常,有100个!如何排列100个项目,但由于您保留了订单,因此可以将问题大小缩小 。你所描述的是integer partitioning problem。例如,假设您将数字5划分为所有可能的整数子集,最多可加5,您将得到集合{5},{4,1},{3,2},{3,1,1 ,},{2,2,1},{2,1,1,1},{1,1,1,1,1}。
整数分区的数量随整数的大小呈指数增长,但指数增长足够慢,您可以枚举n = 100的所有分区,因为它们只有190,569,292。这里的附加约束是你想过滤包含10个项目的所有分区,这很容易通过使用Ferrer图来枚举。
我可以通过将数字20划分为3个桶来演示Ferrer图:从20 col x 3行网格开始,如下所示:
12345678901234567890 1****************** 2* 3*
所以,第一个分区是{18,1,1}
现在将项目从堆栈顶部移动到下一个插槽中:
12345678901234567890 1***************** 2** 3*
我们的新分区是{17,2,1}。我们可以从一个堆栈到另一个堆栈中的另一个项目:
12345678901234567890 1**************** 2*** 3*
现在我们有{16,3,1}。你继续这种方式,直到你列举所有的排列(由你来决定{17,1,2}是否是{17,2,1}的独特分区。)
从这一点开始,您应该能够设想所需算法的大纲 - 也就是说,如果您想要从头开始编写此函数的挑战。其他人已经written lots of efficient functions轻松解决问题。