necessidades C ++ Novato ajuda para a impressão de combinações de números inteiros

StackOverflow https://stackoverflow.com/questions/1876474

  •  18-09-2019
  •  | 
  •  

Pergunta

Suponha que eu sou dado:

  1. Uma gama de números inteiros iRange (isto é, a partir de 1 até iRange) e
  2. Um número de combinações desejado

Eu quero encontrar o número de todas as combinações possíveis e imprimir todas essas combinações.

Por exemplo:

Dada : iRange = 5 e n = 3

Em seguida, o número de combinações é combinações iRange! / ((iRange!-n!)*n!) = 5! / (5-3)! * 3! = 10, ea saída é:

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

Outro exemplo:

Dada : iRange = 4 e n = 2

Em seguida, o número de combinações é combinações iRange! / ((iRange!-n!)*n!) = 4! / (4-2)! * 2! = 6, ea saída é:

12 - 13 - 14 - 23 - 24 - 34

Minha tentativa até agora é:

#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;   
}

Meu problema: A parte do meu código relacionado à impressão das combinações funciona apenas para n = 2, iRange = 4 e eu não posso fazê-lo funcionar em geral, ou seja, para qualquer n e iRange.

Foi útil?

Solução

Aqui está seu código editado: D: D com um recursiva Solução:

#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;
}

Outras dicas

A sua solução só vai trabalhar para n = 2. Pensar em utilizar uma matriz (pentes) com n ints, em seguida, o ciclo irá assinalar-se o último ponto no array. Quando esse item atinge atualização max então pente [n-2] item e definir o último item para o valor anterior +1.

Basicamente a trabalhar como um relógio, mas você precisa lógica para encontrar o que uptick e qual o valor mínimo seguinte é.

parece um bom problema para a recursividade.

Definir um f(prefix, iMin, iMax, n) função, que imprime todas as combinações de dígitos n no intervalo [iMin, iMax] e retorna o número total de combinações. Para n = 1, ele deve imprimir todos os dígitos de iMin para iMax e regresso iMax - iMin + 1.

Para sua iRange = 5 e caso n = 3, você chama f("", 1, 5, 3). A saída deve ser 123 - 124 - 125 - 134 - 135 - 145 - 234 - 235 - 245 - 345.

Observe que o primeiro grupo de saídas são simplesmente 1 prefixado para as saídas de f("", 2, 5, 2), isto é f("1", 2, 5, 2), seguido por f("2", 3, 5, 2) e f("3", 4, 5, 2). Veja como você faria isso com um loop. Entre este, o caso para n = 1 acima, e armadilhas para as entradas ruins (melhor se eles imprimir nada e retornar 0, deve simplificar a sua circular), você deve ser capaz de escrever f().

Eu estou parando porque isso parece uma tarefa de casa. Isso é suficiente para você começar?

EDIT: Apenas para risos, escrevi uma versão Python. Python tem um tempo mais fácil jogando em torno de conjuntos e listas de coisas e ficar legível.

#!/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 que Combos() não se preocupa com os tipos de itens na lista items.

Aqui está um exemplo de uma solução recursiva simples. Eu acredito que existe uma implementação mais ideal se você substituir recursão com ciclos. Poderia ser o seu dever de casa:)

#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;
}

Este é função minha C ++ com diferentes de interface (baseado em STS :: set), mas realizando a mesma tarefa:

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top