正整数 uniq 的组合(顺序不重要)

Posted

技术标签:

【中文标题】正整数 uniq 的组合(顺序不重要)【英文标题】:Combinations of positive integers uniq (order not important) 【发布时间】:2012-09-13 08:39:12 【问题描述】:

所以,我正在为我的问题寻找一个好的解决方案。

我需要生成(打印)整数列表的所有组合,例如: 如果数组包含从 0 到 n-1 的整数,其中 n = 5:

int array[] = 0,1,2,3,4;

组合中整数的顺序并不重要,这意味着 1,1,3、1,3,1 和 3,1,1 实际上是相同的组合,因为它们都包含一个 3 和两个。

所以对于上面的数组,所有长度为3的组合:

0,0,0 -> the 1st combination
0,0,1
0,0,2
0,0,3
0,0,4
0,1,1 -> this combination is 0,1,1, not 0,1,0 because we already have 0,0,1. 
0,1,2
0,1,3
0,1,4
0,2,2 -> this combination is 0,2,2, not 0,2,0 because we already have 0,0,2. 
0,2,3
.
.
0,4,4
1,1,1 -> this combination is 1,1,1, not 1,0,0 because we already have 0,0,1. 
1,1,2
1,1,3
1,1,4
1,2,2 -> this combination is 1,2,2, not 1,2,0 because we already have 0,1,2.
.
.
4,4,4 -> Last combination

现在我为此编写代码,但我的问题是: 如果数组中的数字不是从 0 到 n-1 的整数,假设数组是这样的

int array[] = 1,3,6,7;

我的代码不适用于这种情况,任何用于解决此问题的算法或代码,

这是我的代码:

unsigned int next_combination(unsigned int *ar, int n, unsigned int k)
    unsigned int finished = 0;
    unsigned int changed = 0;
    unsigned int i;

    for (i = k - 1; !finished && !changed; i--) 
        if (ar[i] < n - 1) 
            /* Increment this element */
            ar[i]++;
            if (i < k - 1) 
                /* Make the elements after it the same */
                unsigned int j;
                for (j = i + 1; j < k; j++) 
                    ar[j] = ar[j - 1];
                
            
            changed = 1;
        
        finished = i == 0;
    
    if (!changed) 
        /* Reset to first combination */
        for (i = 0; i < k; i++)
            ar[i] = 0;
        
    
    return changed;

这是主要的:

int main()
    unsigned int numbers[] = 0, 0, 0, 0, 0;
    const unsigned int k = 3;
    unsigned int n = 5;

    do
        for(int i=0 ; i<k ; ++i)
            cout << numbers[i] << " ";
        cout << endl;
    while (next_combination(numbers, n, k));

    return 0;

【问题讨论】:

您必须从一开始就重新考虑这一点。 numbers 是什么?当(据我所知)代码只使用三个时,为什么它有五个元素?你会在哪里存储1,3,6,7?如果next_combination 找到了第k个组合,你不是一遍又一遍地做很多工作吗? 每次的结果组合都存储在数字中,对不起,五个元素没有问题,我的算法,只是从零开始增加数字。 【参考方案1】:

如果您有工作代码来生成从0n-1 的所有数字组合,那么这非常简单。你有你的数字数组:

int array[] = 1,3,6,7;

现在,取n = 4,因为数组中有 4 个项目。生成从 0 到 3 的所有组合,并将它们用作数组的索引。您现在可以通过使用该数组的所有索引组合来获得数组值的所有组合。

【讨论】:

【参考方案2】:

此代码要求“元素池”数组从最小到最大排序,没有重复条目。

函数first_combination 将结果数组(“dist”)初始化为第一个组合。在此之后,next_combination 在循环中被调用,直到它返回 false (就像在您的示例中一样)。 “n”和“k”参数已被替换为获取数组大小的模板参数——因此除了结果之外,枚举函数还需要池数组。

#include <iostream>

template<typename T, int N, int K>
void first_combination(const T (&pool)[N], T (&dist)[K]) 
    for(int ki=0; ki<K; ++ki) 
        dist[ki] = pool[0];
    


template<typename T, int N, int K>
bool next_combination(const T (&pool)[N], T (&dist)[K]) 
    int ni = 0;;
    int ki = 0;

    for(;;) 
        const int prev_ni = ni;
        // search the pool for the value in this slot 
        for(ni=0; pool[ni] != dist[ki]; ++ni) 
            if(ni == N) return false; // slot contains a value not found in the pool
        

        if(++ni < N) break;

        ni = 0;
        dist[ki] = pool[0];
        if(++ki == K) return false;
    

    int v = pool[ni];

    dist[ki] = v;

    // code below assumes pool[] is sorted
    for(--ki; ki>=0; --ki) 
        if(dist[ki] < v) 
            dist[ki] = v;
        
        else 
            v = dist[ki];
        
    

    return true;



template<typename T, int COUNT>
void dumparray( T (&dist)[COUNT]) 
    std::cout << '';
    for(int i=0; i<COUNT; ++i) 
        if(i) std::cout << ',';
        std::cout << dist[i];
    
    std::cout << '' << std::endl;


int main(int argc, char* argv[]) 
    const int pool[] = 1,3,6,7;
    int dist[3] = 0;

    first_combination(pool, dist);
    do 
        dumparray(dist);
     while(next_combination(pool, dist));
    return 0;

【讨论】:

【参考方案3】:

所以你需要生成combination (wiki link)的程序。

这里有完整的描述,甚至可以使用算法:http://compprog.wordpress.com/2007/10/17/generating-combinations-1/

【讨论】:

以上是关于正整数 uniq 的组合(顺序不重要)的主要内容,如果未能解决你的问题,请参考以下文章

将正整数n表示成k个正整数的和(不计各数次序),称为正整数n分为k部分的一个划分,两个划分中,如果各加

关于c语言超长正整数相加的问题,。求高手指教!!!!!

LeetCode——组合总和 Ⅳ

LeetCode——组合总和 Ⅳ

LeetCode 377.组合求和IV

随即产生N个随即两位正整数,并按由大到小的顺序排列,并求中位数 用JAVA程序 急!!!!