在C中创建n个项目的k和m个组合的所有可能子集[重复]
Posted
技术标签:
【中文标题】在C中创建n个项目的k和m个组合的所有可能子集[重复]【英文标题】:Creating all possible subset of k and m combinations of n items in C [duplicate] 【发布时间】:2018-09-02 07:18:08 【问题描述】:我正在寻找解决问题的方法: 我必须编写一个代码来计算唯一元素的组合,即选择作为组的 n 个元素的所有不同组合 k 元素并重新计算剩余子集的新组合,无需复制。 给定 S,所有可能的唯一元素的集合,我必须计算 S 的元素的唯一组合的子集 T,现在我有 重新计算一个新的子集 - V - T 和所有子集 T 和 V 的组合必须是唯一的:
For example I have this set S: 0, 1, 2, 3, 4
我必须得到
a 0, 1 2, 3 4
b 0, 1 2, 4 3
c 0, 1 3, 4 2
d 0, 2 1, 3 4
e 0, 2 1, 4 3
f 0, 2 3, 4 1
g 0, 3 1, 2 4
h 0, 3 1, 4 2
i 0, 3 2, 4 1
j 0, 4 1, 2 3
k 0, 4 1, 3 2
l 0, 4 2, 3 1
discarded as the same as g -> 1, 2 0, 3 4
discarded as the same as j -> 1, 2 0, 4 3
m 1, 2 3, 4 0
discarded as the same as d -> 1, 3 0, 2 4
discarded as the same as k -> 1, 3 0, 4 2
n 1, 3 2, 4 0
discarded as the same as e -> 1, 4 0, 2 3
discarded as the same as h -> 1, 4 0, 3 2
o 1, 4 2, 30
discarded as the same as a -> 2, 3 0, 1 4
discarded as the same as l -> 2, 3 0, 4 1
discarded as the same as o -> 2, 3 1, 4 0
discarded as the same as b -> 2, 4 0, 1 3
discarded as the same as i -> 2, 4 0, 3 1
discarded as the same as n -> 2, 4 1, 3 0
discarded as the same as c -> 3, 4 0, 1 2
discarded as the same as f -> 3, 4 0, 2 1
discarded as the same as m -> 3, 4 1, 2 0
组合 1, 2 0, 3 4 与 0, 3 1, 2 4 的(对于这个问题)相同,然后必须丢弃,与 1, 2 相同0, 4 3 和 0, 4 1, 2 3。
是否有可能在不使用考虑了已经获得的组合的数据结构(作为列表)的情况下达到目标?
我需要这样的东西:Generating Combinations: 1
这不是上一个问题的重复,因为研究涉及必须被认为是单义的分区,即其中包含的元素(无论它们的顺序如何)在以前的细分中必须不是已经同意的,例如 1 , 2 0, 4 3 和 0, 4 1, 2 3 必须被认为是非唯一的,因此只有组合有效:0, 4 1, 2 3
【问题讨论】:
我可能弄错了,但在您的示例中,您为 5 个元素的独特组合提供了 24 个可能的结果。通常不是 120 个结果吗? 2, 1 0, 3 4 在哪里?此外,T 子集的值是否强制配对?不能是 0, 1, 23, 4 吗?你能给出一个 S 中 3 和 4 元素的完整例子吗? @Tom 的 2, 1 0, 3 4 不存在,因为不同的订单(在一个集合内)被认为是相同的组合,所以 2, 1 0 , 3 4 与 0, 3 1, 2 4 相同。 T 不是强制配对的,在本例中是配对的。 因此,每个“组合”是一组无序的n/k
无序的k
元素集,以及一个无序的n%k
元素集,每个完整“组合”中的所有唯一元素,取自一组 n
独特元素,k
固定。对我来说,这听起来很像一个分组问题(组合问题的一个子类型)。有趣..
rosettacode.org/wiki/Combinations#C
@nullqube 感谢您的建议,但递归代码并没有完全按照要求执行,并且最后的非递归代码在分段错误中崩溃
【参考方案1】:
这比我最初想象的要复杂。
好的,假设你有“n”个 uniq 元素。 uniq 可能性的总数是“n!” (所以对于 5 个元素,你有 120 种可能性)。
假设您想将“k”个数字组成“组”。
因此,如果 n = 5 且 k = 2,您将得到您的示例:
0, 1, 2, 3, 4。
现在,乐趣就从这里开始: 为了知道当前命题是否不是重复的,您可以丢弃每个 complete 组中的第一个数字未排序的每个命题。
例如:
0, 1, 2, 3, 4。
在这里,1 和 3 是无用的,因为它不是完整组的第一个值,而 4 是不完整组的一部分。 所以有趣的是
0, ?, 2, ?, ?。
0, 2 是否已排序?是的,所以你可以保留这个提议。 这意味着如果你有
2, 3, 0, 1, 4。
不好,因为
2, ?, 0, ?, ?。
2, 0 未排序。
如果你有 n = 6 和 k = 2,那么是
0, 2, 3, 4, 1, 5
有效吗?不,因为 0 3 1 未排序。 你可以看到
0, 2, 1, 5 , 3, 4
是有效的排序命题。
现在,如果我们知道 n 和 k,是否有可能计算出有多少个有效命题?
是的。
也许吧。 我想 ... 如果我能找到什么,我会更新。
编辑:
Aaaaannnd,这里是一个实现。做点有趣的事... 它基于前面的算法,所以当然如果我的算法是假的,那么这段代码就是假的。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 5
#define K 2
void Comb_Display(int proposition[N])
printf("");
for (int i = 0; i < N; ++i)
if (i && i % K == 0)
printf(" ");
printf("%d%s", proposition[i], (i && (i + 1) % K == 0) || i + 1 >= N ? "" : ", ");
printf("\n");
bool Comb_Valid(int proposition[N])
int nbGroup = N / K;
if (nbGroup == 1)
return (true);
for (int i = 0; i < nbGroup; i += K)
if (proposition[i] > proposition[i + K])
return (false);
return (true);
void Comb_MakeMagicPlease(int numberAvailable[N], int proposition[N], int ind)
// We are at the end of the array, so we have a proposition
if (ind >= N)
printf("%s : ", Comb_Valid(proposition) ? "OK" : " "); // O = Valide, ' ' = invalide
Comb_Display(proposition);
return;
// We scan "numberAvailable" in order to find the first number available
for (int i = 0; i < N; i++)
if (numberAvailable[i] != -1)
int number = numberAvailable[i];
numberAvailable[i] = -1; // We mark the number as not available
proposition[ind] = number;
Comb_MakeMagicPlease(numberAvailable, proposition, ind + 1);
numberAvailable[i] = number; // we mark the number as available
int main(void)
int numberAvailable[N];
int proposition[N];
for (int i = 0; i < N; ++i)
numberAvailable[i] = i + 1;
Comb_MakeMagicPlease(numberAvailable, proposition, 0);
return 0;
【讨论】:
如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review 感谢您的信息,我会记住的,但这更像是一个悬而未决的问题,而不是一个真正的问题。 @Tom 感谢您的代码,但它有一个错误,它返回 OK : 1, 5 2, 3 4 and 2, 3 5, 1 4 作为“OK”值,但实际上它们是相同的值,所以只有没有一个可以是“OK” 那么你只需要修改“Comb_Valid”函数来检查每个子集 ., ., . 是否在内部排序。为什么要排序?因为如果我们有一个子网的元素“a,b,c”,那么你可以有 6 个子网:abc,acb,bac,bca,cab,cba。我们怎么能只保留一个?好吧,我们可以看到,当其他 5 个没有排序时,只有一个是“排序的”(abc)。这与子网组的原理相同。那么,既然您知道每个子网可以保留或不保留,这取决于是否已排序,为什么不尝试一下呢? @Tom's,你能更新你的代码吗?【参考方案2】:是的。
在这种情况下,请确保结果已排序。这样你只输出一个排序的版本,而不必检查是否已经获得了组合。
您也可以使用它来加快生成速度。 IE。选择 1,2 后,尝试以 0 开头的任何内容都没有意义,因此您可以跳过这些内容。
【讨论】:
你能帮我用 C 语言的算法或代码吗?以上是关于在C中创建n个项目的k和m个组合的所有可能子集[重复]的主要内容,如果未能解决你的问题,请参考以下文章
已知n个正数:wi, 1<=i<=n, 和M。要求找出{wi }的所有子集使得子集内元素之和等于M。例如: n=4, (w1,w2,w3,w4)=(11,13,24,7),