简体   繁体   English

C++ 新手需要帮助打印整数组合

[英]C++ Newbie needs helps for printing combinations of integers

Suppose I am given:假设我得到:

  1. A range of integers iRange (ie from 1 up to iRange ) and整数范围iRange (即从1iRange )和
  2. A desired number of combinations所需的组合数

I want to find the number of all possible combinations and print out all these combinations.我想找到所有可能组合的数量并打印出所有这些组合。

For example:例如:

Given : iRange = 5 and n = 3给定iRange = 5n = 3

Then the number of combinations is iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10那么组合数就是iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10 iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10 iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10 combinations, and the output is: iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10组合,输出为:

123 - 124 - 125 - 134 - 135 - 145 - 234 - 235 - 245 - 345

Another example:另一个例子:

Given : iRange = 4 and n = 2给定iRange = 4n = 2

Then the number of combinations is iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6那么组合数就是iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6 iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6 iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6 combinations, and the output is: iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6组合,输出为:

12 - 13 - 14 - 23 - 24 - 34

My attempt so far is:到目前为止,我的尝试是:

#include <iostream>
using namespace std;

int iRange= 0;
int iN=0;

int fact(int n)
{
    if ( n<1)
        return 1;
    else
    return fact(n-1)*n;
}

void print_combinations(int n, int iMxM)
{
    int iBigSetFact=fact(iMxM);
    int iDiffFact=fact(iMxM-n);
    int iSmallSetFact=fact(n);
    int iNoTotComb = (iBigSetFact/(iDiffFact*iSmallSetFact));
    cout<<"The number of possible combinations is: "<<iNoTotComb<<endl;
    cout<<" and these combinations are the following: "<<endl;


    int i, j, k;
    for (i = 0; i < iMxM - 1; i++)
    {
        for (j = i + 1; j < iMxM ; j++)
        {
            //for (k = j + 1; k < iMxM; k++)
                cout<<i+1<<j+1<<endl;
        }
    }
}

int main()
{
    cout<<"Please give the range (max) within which the combinations are to be found: "<<endl;
    cin>>iRange;
    cout<<"Please give the desired number of combinations: "<<endl; 
    cin>>iN;
    print_combinations(iN,iRange);
    return 0;   
}

My problem: The part of my code related to the printing of the combinations works only for n = 2, iRange = 4 and I can't make it work in general, ie, for any n and iRange .我的问题:我的代码中与组合打印相关的部分仅适用于n = 2, iRange = 4并且我无法使其在一般情况下工作,即对于任何niRange

Your solution will only ever work for n=2.您的解决方案仅适用于 n=2。 Think about using an array (combs) with n ints, then the loop will tick up the last item in the array.考虑使用具有 n 个整数的数组(梳子),然后循环将勾选数组中的最后一项。 When that item reaches max update then comb[n-2] item and set the last item to the previous value +1.当该项目达到最大更新时,comb[n-2] 项目并将最后一个项目设置为先前的值 +1。

Basically working like a clock but you need logic to find what to uptick and what the next minimum value is.基本上像时钟一样工作,但您需要逻辑来找到要上升的内容以及下一个最小值是什么。

Looks like a good problem for recursion.看起来是递归的一个好问题。

Define a function f(prefix, iMin, iMax, n) , that prints all combinations of n digits in the range [ iMin , iMax ] and returns the total number of combinations.定义一个函数f(prefix, iMin, iMax, n) ,它打印 [ iMin , iMax ] 范围内n位数字的所有组合并返回组合的总数。 For n = 1, it should print every digit from iMin to iMax and return iMax - iMin + 1 .对于n = 1,它应该打印从iMiniMax每个数字并返回iMax - iMin + 1

For your iRange = 5 and n = 3 case, you call f("", 1, 5, 3) .对于iRange = 5n = 3情况,您调用f("", 1, 5, 3) The output should be 123 - 124 - 125 - 134 - 135 - 145 - 234 - 235 - 245 - 345 .输出应该是123 - 124 - 125 - 134 - 135 - 145 - 234 - 235 - 245 - 345

Notice that the first group of outputs are simply 1 prefixed onto the outputs of f("", 2, 5, 2) , ie f("1", 2, 5, 2) , followed by f("2", 3, 5, 2) and f("3", 4, 5, 2) .请注意,第一组输出只是1前缀到f("", 2, 5, 2) ,即f("1", 2, 5, 2) ,然后是f("2", 3, 5, 2)f("3", 4, 5, 2) See how you would do that with a loop.看看你会如何用循环来做到这一点。 Between this, the case for n = 1 above, and traps for bad inputs (best if they print nothing and return 0, it should simplify your loop), you should be able to write f() .在此之间,上面n = 1 的情况,以及错误输入的陷阱(最好是不打印任何内容并返回 0,它应该可以简化您的循环),您应该能够编写f()

I'm stopping short because this looks like a homework assignment.我停了下来,因为这看起来像是一项家庭作业。 Is this enough to get you started?这足以让你开始吗?

EDIT: Just for giggles, I wrote a Python version.编辑:只是为了傻笑,我写了一个 Python 版本。 Python has an easier time throwing around sets and lists of things and staying legible. Python 可以更轻松地处理事物的集合和列表并保持清晰易读。

#!/usr/bin/env python

def Combos(items, n):
    if n <= 0 or len(items) == 0:
        return []
    if n == 1:
        return [[x] for x in items]
    result = []
    for k in range(len(items) - n + 1):
        for s in Combos(items[k+1:], n - 1):
            result.append([items[k]] + s)
    return result

comb = Combos([str(x) for x in range(1, 6)], 3)
print len(comb), " - ".join(["".join(c) for c in comb])

Note that Combos() doesn't care about the types of the items in the items list.请注意, Combos()不关心items列表中项目的类型。

Here's an example of a plain recursive solution.这是一个简单的递归解决方案的例子。 I believe there exists a more optimal implementation if you replace recursion with cycles.我相信如果您用循环替换递归,则存在更优化的实现。 It could be your homework :)这可能是你的家庭作业:)

#include <stdio.h>

const int iRange = 9;
const int n = 4;


// A more efficient way to calculate binomial coefficient, in my opinion
int Cnm(int n, int m)
{
    int i;
    int result = 1;

    for (i = m + 1; i <= n; ++i)
        result *= i;

    for (i = n - m; i > 1; --i)
        result /= i;

    return result;
}


print_digits(int *digits)
{
    int i;
    for (i = 0; i < n; ++i) {
        printf("%d", digits[i]);
    }
    printf("\n");
}

void plus_one(int *digits, int index)
{
    int i;

    // Increment current digit
    ++digits[index];

    // If it is the leftmost digit, run to the right, setup all the others
    if (index == 0) {
        for (i = 1; i < n; ++i)
            digits[i] = digits[i-1] + 1;
    }
    // step back by one digit recursively
    else if (digits[index] > iRange) {
        plus_one(digits, index - 1);
    }
    // otherwise run to the right, setting up other digits, and break the recursion once a digit exceeds iRange
    else {
        for (i = index + 1; i < n; ++i) {
            digits[i] = digits[i-1] + 1;

            if (digits[i] > iRange) {
                plus_one(digits, i - 1);
                break;
            }
        }
    }
}

int main()
{
    int i;
    int digits[n];

    for (i = 0; i < n; ++i) {
        digits[i] = i + 1;
    }

    printf("%d\n\n", Cnm(iRange, n));

    // *** This loop has been updated ***
    while (digits[0] <= iRange - n + 1) {
        print_digits(digits);
        plus_one(digits, n - 1);
    }

    return 0;
}

Here is your code edited :D :D with a recursive solution:这是您使用递归解决方案编辑的代码 :D :D :

#include <iostream>

int iRange=0;   
int iN=0;           //Number of items taken from iRange, for which u want to print out the combinations
int iTotalCombs=0;
int* pTheRange;
int* pTempRange;

int find_factorial(int n)
{
    if ( n<1)
        return 1;
    else
    return find_factorial(n-1)*n;
}

//--->Here is another solution:
void print_out_combinations(int *P, int K, int n_i) 
{
    if (K == 0)
    {
        for (int j =iN;j>0;j--)
        std::cout<<P[j]<<" ";
        std::cout<<std::endl;
    }
    else
        for (int i = n_i; i < iRange; i++) 
        {
            P[K] = pTheRange[i];
            print_out_combinations(P, K-1, i+1);
        }
}
//Here ends the solution...

int main() 
{
    std::cout<<"Give the set of items -iRange- = ";
    std::cin>>iRange;
    std::cout<<"Give the items # -iN- of iRange for which the combinations will be created = ";
    std::cin>>iN;

    pTheRange = new int[iRange];
    for (int i = 0;i<iRange;i++)
    {
        pTheRange[i]=i+1;
    }
    pTempRange = new int[iN];

    iTotalCombs = (find_factorial(iRange)/(find_factorial(iRange-iN)*find_factorial(iN)));

    std::cout<<"The number of possible combinations is: "<<iTotalCombs<<std::endl;
    std::cout<<"i.e.the combinations of "<<iN<<" elements drawn from a set of size "<<iRange<<" are: "<<std::endl;
    print_out_combinations(pTempRange, iN, 0);
    return 0;
}

This is my C++ function with different interface (based on sts::set) but performing the same task:这是我的 C++ 函数,具有不同的接口(基于 sts::set)但执行相同的任务:

typedef std::set<int> NumbersSet;
typedef std::set<NumbersSet> CombinationsSet;

CombinationsSet MakeCombinations(const NumbersSet& numbers, int count)
{
  CombinationsSet result;

  if (!count) throw std::exception();

  if (count == numbers.size())
  {
    result.insert(NumbersSet(numbers.begin(), numbers.end()));
    return result;
  }

  // combinations with 1 element
  if (!(count - 1) || (numbers.size() <= 1))
  {
    for (auto number = numbers.begin(); number != numbers.end(); ++number)
    {
      NumbersSet single_combination;
      single_combination.insert(*number);
      result.insert(single_combination);
    }
    return result;
  }

  // Combinations with (count - 1) without current number
  int first_num = *numbers.begin();
  NumbersSet truncated_numbers = numbers;
  truncated_numbers.erase(first_num);
  CombinationsSet subcombinations = MakeCombinations(truncated_numbers, count - 1);

  for (auto subcombination = subcombinations.begin(); subcombination != subcombinations.end(); ++subcombination)
  {
    NumbersSet cmb = *subcombination;
    // Add current number
    cmb.insert(first_num);
    result.insert(cmb);
  }

  // Combinations with (count) without current number
  subcombinations = MakeCombinations(truncated_numbers, count);
  result.insert(subcombinations.begin(), subcombinations.end());

  return result;
}

I created a next_combination() function similar to next_permutation() , but valid input is required to make it work我创建了一个类似于next_permutation()next_combination()函数,但需要有效的输入才能使其工作

//nums should always be in ascending order

    vector <int> next_combination(vector<int>nums, int max){
    int size = nums.size();
    
    if(nums[size-1]+1<=max){
        nums[size-1]++;
        return nums;
    }else{
        if(nums[0] == max - (size -1)){
            nums[0] = -1;
            return nums; 
        }
        
        int pos;
        int negate = -1;
        for(int i = size-2; i>=0; i--){
            if(nums[i]+1 <= max + negate){
                pos = i;
                break;
            }
            negate --;
        }
        nums[pos]++;
        pos++;
        while(pos<size){
            nums[pos] = nums[pos-1]+1;
            pos++;
        }
    }
    return nums;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM