Algoritmo para Loto-Aplicações – De CSN para combinações e de combinações para CSN
O CSN é número sequencial combinatórico (combinatorial sequence number) de uma dada combinação, quando estas se encontram ordenadas lexicograficamente (por ordem numérica, pronto).
Publicado Tuesday, January 19, 2010 at 1:10 AM
Uma forma de calcular os CSN, e vice-versa, seria simplesmente construir todo o desdobramento até ao CSN pretendido, ou até à chave pretendida. Don’t. É estúpido, é um desperdício de ciclos de processamento e é péssima programação. Sobretudo, se já alguém pensou no assunto e se os algoritmos são do domínio público.
Vamos então aos ditos…
O algoritmo para calcular a combinação a partir do CSN é um engenhosa obra prima de B. P. Buckles e M. Lyabanon, publicada em 1974.
1função csnParaCombinacao(csn, n, k)2 seja limite_inferior = 0;3 seja r = 0;4 seja combinação = [0...k-1]56 para cada i, sendo i = 0, enquanto i < k - 1, incrementar i7 combinação[i] = 0;8 se(i != 0) combinação[i] = combinação[i - 1];910 fazer11 combinação[i] = combinação[i] + 1;12 // lembram-se desta função?13 r = numeroDeCombinacoes(n - combinação[i], (k - 1) - i);14 limite_inferior = limite_inferior + r;15 enquanto (limite_inferior < csn);1617 limite_inferior = limite_inferior - r;18 fim de para;1920 combinação[k - 1] = combinação[k - 2] + csn - limite_inferior;2122 devolve combinação;23fim de função;
Para começar, quero-vos dizer que parece bem mais complicado do que, na realidade, é.
Depois, reparem como a última posição da combinação é tratada à parte, duma maneira perfeitamente elegante, usando os valores do CSN pedido e do último limite inferior calculado.
Mas passemos, então, à manobra inversa, calcular o CSN a partir da combinação. O seguinte algoritmo não tem, que eu saiba, autores oficiais. A sua simplicidade decorre de ser um negativo quase perfeito da função anterior.
1função combinacaoParaCsn(combinação, n)2 seja k = combinação.tamanho();3 seja limite_inferior = 0;4 seja r= 0;56 para cada i, sendo i = 1, enquanto i <= k, incrementar i7 r = n - combinação[k - i];8 se (r >= i)9 limite_inferior = limite_inferior + númeroDeCombinações(r, i);10 fim de se;11 fim de para;1213 devolve numeroDeCombinacoes(n, k) - limite_inferior;14fim de função;
Podem ver, na segunda instrução do para
, que a combinação está a ser percorrida de trás para a
frente, e o limite inferior está a ser contado como o que falta até ao fim, sendo finalmente
subtraído ao número de combinações total para nos dar o CSN.