Sie sind auf Seite 1von 7

Um Tutorial sobre

Gerando Permutações usando a Representação Fatorádica de Números

Prof. Joel G. Silva Filho Instituto de Educação Superior de Brasília - IESB joel-iesb@joelguilherme.com

2012-01-05

Palavras-chave: permutações, inversões, sistemas numéricos, números factorádicos, geração de permutações.

Introdução A permutação de um conjunto ordenado de n elementos é um conceito bem conhecido. Quaisquer que sejam os elementos do conjunto, por simplicidade e facilidade de manipulação, podemos sempre representá-lo pelo conjunto dos n primeiros inteiros não negativos, ou, em outras palavras, os inteiros módulo-n: Z n = {0,1,2, … ,n-1}. Uma permutação sobre este conjunto é simplesmente uma reordenação de seus elementos, = ((0),(1), … , (n-1)), onde (i) é o elemento que substitui i na i-ésima posição. Por exemplo, qualquer conjunto de 4 elementos pode ser representado por Z 4 = {0,1,2,3}. Podemos ter então, por exemplo, 2 = {0,2,1,3} - explicaremos mais tarde o porque do subscrito '2', onde 2 (0) = 0, 2 (1) = 2, 2 (2) = 1 e 2 (3) = 3.

Conjuntos ordenados e suas permutações encontram extensa aplicação e interesse em muitas áreas, tais como matemática discreta, combinatória, criptografia, ciência da computação, e outras. Uma questão básica quando estudamos permutações é saber quantas permutações distintas de um conjunto de n elementos podemos encontrar. Considerando que todos os elementos conjunto em questão sejam distintos, a resposta é fácil de encontrar: temos n possíveis posições para cada elemento, havendo n escolhas para o primeiro, (n-1) para o segundo, (n-2) para o terceiro, e assim por diante, até que para a última posição teremos apenas uma escolha, quando todos os outros já tiverem sido escolhidos, obtendo-se N = n(n-1)(n-2)321 possibilidades totais de escolha, o qual é um número que recebe a representação especial n! e é chamado de fatorial de n (leia-se “n fatorial”). O conjunto de todas estas permutações de n elementos é usualmente denotada por S n e forma a estrutura de um Grupo sob a operação de 'composição de permutações', i.e. a aplicação de duas ou mais permutações sobre um dado conjunto, que constitui o Grupo de Simetria de ordem n (1) .

Sistemas de Numeração Estamos acostumados a representações numéricas de base simples, tal como a base 10, que nos fornece os números decimais de nosso dia a dia, e a base 2, que nos fornece os números binários, estes últimos sendo a base para todas as operações em computadores digitais. Dada uma base genérica b, podemos representar qualquer número nesta base como

N = d n-1 b n-1 +d n-2 b n-2 + … +d 2 b 2 +d 1 b 1 +d 0 b 0

onde d i , i = 0,

(b-1)]. Para a representação na base 10 os dígitos estão

na faixa [0

representação é denominada uma representação polinomial, uma vez que cada dígito pode ser visto como o coeficiente de um polinômio na base b. Além disso, a ordem, ou posição, de cada dígito assume um valor que é proporcional à correspondente potência da base, e assim esta representação é também vista como uma representação posicional. Sistemas sobre outras bases foram desenvolvidos através da história, e mesmo sistemas sem uma base e não posicionais, como o sistema de numeração romana (2) .

, (n-1) - para um número de n dígitos - são os dígitos nesta representação

numéricas, cada dígito estando na faixa [0

9], e para a representação binária (base 2) os dígitos estão na faixa [0,1]. Esta

Quando várias bases estão em consideração, se costuma utilizar um subscrito aposto ao número para identificar a base em que está representado. Por exemplo, o número decimal 123 pode ser escrito como 123 10 , o que deve ser interpretado como

N = 123 10 = 1 2 + 2 1 + 3 0

dando origem aos valores posicionais familiares de unidades, dezenas, centenas, e assim por diante. Este mesmo número pode também ser representado em binário como

N = 123 10 = 1111011 2 = 1 6 + 1 5 + 1 4 + 1 3 + 0 2 + 1 1 + 1 0 .

Números Fatorádicos Agora, o que é um número fatorádico? Um número fatorádico é também uma representação posicional para um número onde uma base distinta é utilizada para cada dígito, mas o valor da posição não é proporcional a uma potência da base, mas sim ao seu fatorial. Sendo assim, este sistema é visto como um sistema de base mista. A conjunção dos termos “fatorial” e “base mista” (em inglês) levou ao termo “fatorádico”, embora outros termos tenham sido cunhados e utilizados na literatura (3) . Qualquer número N < n! pode ser representado por um número fatorádico único de n dígitos, na forma

N ! = d n-1 .(n-1)!+d n-2 .(n-2)!+ … +d 2 .2!+d 1 .1!+d 0 .0!

o que, de forma compacta, escrevemos como N ! = (d n-1 d n-2 … d 2 d 1 d 0 ) ! ,

do mesmo modo como o fazemos para um número em qualquer sistema ordinário de base fixa. Observe o uso do subscrito '!' para indicar que o número está em notação fatorádica. Deve também ser observado que, para um número fatorádico:

(n-1), é um dígito base-(i +1), de modo

o i-ésimo dígito da direita para a esquerda, i = 0 que devemos ter d i i;

o 1 o dígito, aquele para i = 0, sempre será zero, tal que ele não não contribui efetivamente para o valor total do número (e poderia mesmo ser omitido, sem perda de representação, como fazem alguns autores);

o valor posicional do i-ésimo dígito é i!. Por exemplo, um número que seja menor que 5! ( = 120 10 ) pode ser expresso como um número fatorádico de 5 dígitos

N ! = (d 4 d 3 d 2 d 1 d 0 ) !

e, tomando como exemplo N = 83 10 , então temos

N ! = 31210 ! = 34! + 13! + 22! +11! + 00!

= 324 + 16 + 22 +11 + 01

= 72 + 6 +4 + 1 + 0

= 83 10 De agora em diante, aonde não indicado de outra forma, utilizaremos números sem subscritos para expressar números decimais, de modo que escreveremos 31210 ! = 83.

n 1

Por indução, pode-se provar que n ! = ii ! + 1. Como exemplo, o maior número

i = 0

fatorádico de 5 dígitos (n = 5) é 43210 ! , o qual tem como próximo valor (43210 ! +1) = 100000 ! . Em outras palavras, 44!+3!+2!+1!+! = 119 e, 5! =120 = 119+1. Isto estabelece que, realmente, qualquer inteiro não negativo tem uma representação única como um número fatorádico. A conversão de um número decimal em sua representação fatorádica pode ser feita pelo método direto de divisões sucessivas pelo valor posicional de cada dígito, iniciando pelo posição de maior ordem, i = n-1, tomando-se os quocientes como os correspondentes dígitos fatorádicos. O resto de cada divisão é então dividido pelo próximo valor posicional, e assim por diante. Considerando o exemplo anterior poderíamos ter computado

83

= 324 + 11

11

= 1 + 5

5

= 2 + 1

1

= 1 + 0

0

= 0 + 0

Inversões

Considere um conjunto de n = 5 elementos, representado por Z 5 = {0,1,2,3,4}, e vamos

denominar os elementos do conjunto como p i , para i = 0

conjunto é 0 = (0,1,2,3,4), que representa a permutação identidade, uma vez que a ordem original dos elementos não foi alterada. Uma outra permutação poderia ser 83 = (3,1,4,2,0) - como mencionado antes, vamos esclarecer o uso destes subscritos posteriormente. Diz-se que uma inversão ocorreu na posição i, para qualquer dada permutação, quando p i > p j , para algum j > i. Em 83 , para i = 0 nós temos 3 inversões, uma vez que 4 > 2, 3 e 1. Da mesma forma, para i = 1 temos 1 inversão, para i = 2 temos 2 inversões, para i = 3 temos 1 inversão, e para i = 4 temos 0 inversões. Nós sempre teremos 0 inversões para i = (n-1) uma vez que este é o último elemento. Se colocarmos estas contagens de inversões na forma de um vetor teremos o que é denominado de vetor de inversões da permutação, ou tabela de inversões, ou ainda o código de Lehmer (4,5) , L. Para o caso geral podemos escrever

(n-1). Uma possível permutação deste

L() = [l 0 (), l 1 (), … , l n-1 ()], onde

l i () = |{j > i: (i) > (j)}|.

Pode ser mostrado que toda permutação tem um código de Lehmer único associado, existindo assim uma correspondência biunívoca entre códigos de Lehmer e permutações (3) . Retornando ao nosso exemplo anterior, verificamos que L 83 = [3,1,2,1,0].

Agora, a beleza dessa construção: 83 = 31210 ! , o que nos mostra que podemos associar cada número fatorádico distinto de n dígitos com cada permutação pertencente a S n . Isto finalmente justifica o uso dos subscritos para identificar as permutações exemplificadas anteriormente e nos dá uma forma muito simples de enumerar todas as permutações em S n com um simples índice decimal que conta de 0 a (n! - 1). Outro importante resultado desta ordenação das permutações como números fatorádicos é que a sequência das mesmas corresponde à ordenação natural, ou lexicográfica. Como mais um pequeno exemplo, tomemos n = 3 e vamos construir uma tabela associando todos os 6 elementos de S 3 aos seus correspondentes índices, tanto em decimal quanto na representação fatorádica, como mostrado na tabela 1 abaixo:

Tabela 1: permutações e índices associados para n = 3.

N

N

!

N

0

(0,0,0)

(0,1,2)

1

(0,1,0)

(0,2,1)

2

(1,0,0)

(1,0,2)

3

(1,1,0)

(1,2,0)

4

(2,0,0)

(2,0,1)

5

(2,1,0)

(2,1,0)

De Permutações para Números Fatorádicos e Vice-versa Mostramos como representar uma dada permutação como um número fatorádico, simplesmente construindo-se seu vetor de inversões. Agora resta apenas mostrarmos como determinar a permutação particular associada a um dado número fatorádico ou a seu decimal equivalente. existem muitas e muitas formas de se gerar permutações, incluindo geração sequencial e geração aleatória. O ponto importante em relação à geração via o número fatorádico associado é a possibilidade de gerar qualquer permutação sem se ter que passar por processos intermediários, assim como, dada uma permutação, se obter facilmente um índice para a mesma, considerando um ordenamento lexicográfico dos elementos de S n .

Para obter a permutação de n elementos a partir de seu correspondente valor fatorádico, ou equivalentemente, seu código de Lehmer, ou vetor de inversões, é apenas uma questão de trafegarmos ao contrário em relação à construção anterior. Considere o caso de n = 5, tal que o conjunto original possa ser considerado como S = 0 = {0,1,2,3,4}. Vamos supor que queremos determinar quem é 51 . Considerando que N = 51 = 20110 ! , então podemos escrever L(51 ) = [l 0 , l 1 , l 2 , l 3 , l 4 ] = [2,0,1,1,0]. Iniciando com i = 0, observamos que l 0 = 2 corresponde à contagem de inversões para aquela posição. Assim, para determinarmos o correspondente elemento em 0 simplesmente o que temos que fazer é buscar o elemento do conjunto original que é maior que 2 outros elementos, o que, por sua vez, se mostra ser o elemento de ordem 2 em 0 , ou ainda, 51 (0) = 0 (l 0 ) = 0 (2) = 2. Agora nós removemos este elemento, 2, do conjunto original (já foi utilizado em 51 ), obtendo 0 ' = {0,1,3,4}. Considere agora o próximo elemento de L, l 1 = 0. O mesmo processo agora se aplica a 0 ', fornecendo 51 (1) = 0 '(l 1 ) = 0 '(0) = 0, e assim sucessivamente, até obtermos todos os elementos da permutação desejada. Na tabela 2 que se segue está melhor ilustrado este processo de construção de 51 :

Tabela 2: Construindo a permutação 51 (n=5) a partir de seu código de Lehmer.

i

l

i

Lehmer Code

Set S (0 )

Perm 51

0

2

[2,0,1,1,0]

(0,1,2,3,4)

(2,_,_,_,_)

1

0

[2,0,1,1,0]

(0,1,3,4,_)

(2,0,_,_,_)

2

1

[2,0,1,1,0]

(1,3,4,_,_)

(2,0,3,_,_)

3

1

[2,0,1,1,0]

(1,4,_,_,_)

(2,0,3,4,_)

4

0

[2,0,1,1,0]

(1,_,_,_,_)

(2,0,3,4,1)

Observe que l n-1 sendo sempre zero, ele corresponde a qualquer que seja o último elemento restante em 0 ' no último passo do processo.

Gerando uma permutação

permutação

correspondente através deste simples algoritmo, em pseudo linguagem:

Dada

o

ordem

n

e

um

índice

decimal

N

<

(n-1)!

podemos

gerar

a

1. Define variables:

N,n: int;

// Decimal integer and order of the set

i,j,r,v: int; // indexes to arrays

S: array[0

Perm: array[0

PlaceValue: array[0

Factoradic:array[0

n-1];

// original set

n-1];

// permuted set

n-1];

n-1];

// fatoradic place values [0!,1!,2!, // fatoradic digits corresponding to N

2. Initialize variables

2.1 read n,N

,(n-1)!]

3.

Convert N to factoradic

3.1 V = N

3.2 for i from (n-1) downto 0 do Factoradic[i] = V div PlaceValue[i] V = V mod PlaceValue[i] enddo

4. Convert Factoradic to permutação for i from 0 to (n-1) do

j

= (n-1)-i

r

= Factoradic[j]

Perm[i] = S[r] // delete S[r] by shifting left greater order elements for j from r to (n-2) do S[j] = S[j+1]

enddo

END

Uma implementação de demonstração em FreePascal deste algoritmo é mostrada abaixo, junto com sua saída para n = 5 e N = 51, como feito no exemplo mostrado:

program Dec2Perm;

(*

Program for generating a permutação of a set of n elements from a given Decimal index, based on the representation of a permutação as a "factoradic

number", i.e. a number represented in the mixed base [(n-1)!,(n-2)!, 1!, 0!].

We have limited 'n' to 12, as this is just a demo program and 12! fits into

,2!,

 

a

32-bit CPU word.

*)

uses SysUtils;

const progname = 'Dec2Perm'; version = 'v0.9 - 12.01.03'; author = ' (Joel Guilherme)'; nmax = 12;

type aset = array[0

(nmax-1)]

of byte;

// a set of integers mod-n

bset = array[0

(nmax-1)]

of longword; // a set of integers

var

n: byte;

// the order of the set

D,V: longword;

// decimal to be converted to a permutação

Dmax: longword;

// maximum value for D

i,j,r: byte;

// indexes to arrays

Code: word;

// indicates input conversion error

S: aset;

// this will hold the original, ordered permutação (0,1,2,

,n-1)

Perm: aset;

// the permutação associated to N

PlaceValue: bset; // array with fatoradic place values [0!,1!,2!, ,(n-1)!] Factoradic: bset; // array with a fatoradic number digits corresponding to N

procedure ShowSet(msg: string; span: byte; var Arr: aset); // writes a set to console var

r,m: byte;

begin

m := span-1;

write(msg); for r := 0 to m do begin if (r = 0) then write('[',Arr[r]) else write(',',Arr[r]); end; writeln(']'); end; { ShowSet }

procedure ShowFac(msg: string; span: byte; var Arr: bset); // writes a factoradic array to console var

r,m: byte;

begin

m := span-1;

write(msg);

for r := m downto 0 do begin if (r = m) then write('[',Arr[r])

else

write(',',Arr[r]);

end; writeln(']'); end; { ShowFac }

function factorial(x: longword): longword; begin if (x=0) or (x=1) then factorial := 1 else factorial := x*factorial(x-1);

end;

procedure Help; // Shows a "help" message if wrong parameters passed begin writeln('usage:');

writeln('

> nextperm <N> <n>');

writeln('

where');

writeln('

- N is a decimal index to a lexicographically permuted set');

writeln('

- n is the order of the set to be permuted');

writeln;

halt(1);

end;

procedure Error(msg: string); begin writeln(msg,'! Aborting!');

halt(1);

end;

procedure Initialize; // initialize arrays and variables begin Dmax := factorial(n); for i := 0 to (n-1) do begin S[i] := i; PlaceValue[i] := factorial(i); end; end;

{ Main Program }

begin writeln; writeln(Progname,' ',version); writeln('Program for generating a lexicographically ordered '); writeln('permutação from a given decimal index. - ',author); writeln; if paramcount < 2 then Help;

val(paramstr(1),D,Code);

if Code > 0 then Error('Error reading input N');

val(paramstr(2),n,Code);

if Code > 0 then Error('Error reading input n'); if n > nmax then Error('Given order ''n'' is too big. Maximum is 12'); Initialize; if D > Dmax then Error('Given decimal ''N'' is too big. Maximu is (n! - 1)'); // Convert N to Factoradic V := D; for i := (n-1) downto 0 do begin Factoradic[i] := V div Placevalue[i];

V

:= V mod Placevalue[i];

end;

writeln('For n = ',n,':');

ShowSet('Perm(0)

= ',n,S);

ShowFac('Factoradic('+inttostr(D)+') = ',n,Factoradic); // Convert Factoradic to permutação for i := 0 to (n-1) do begin

j := (n-1) - i;

r := Factoradic[j]; Perm[i] := S[r];

// delete S[r] from S (by shifting left all greater order elements) for j := r to (n-2) do S[j] := S[j+1]; end;

ShowSet('Perm('+inttostr(D)+')

writeln;

= ',n,Perm);

end.

O programa foi compilado com FreePascal 2.4.0 para o Linux-Ubuntu 10.04. Uma saída de amostra para o programa é:

$ ./Dec2Perm 51 5

Dec2Perm v0.9a - 12.01.03 Program for generating a lexicographically ordered permutation from a given decimal index. - (Joel Guilherme)

For n = 5:

Perm(0) = [0,1,2,3,4]

Factoradic(51) = [2,0,1,1,0]

Perm(51)

= [2,0,3,4,1]

Bibliografia (1) Symmetric group, http://en.wikipedia.org/wiki/Symmetric_group - acessado em 11/12/2011. (2) Positional notation, http://en.wikipedia.org/wiki/Positional_notation - acessado em 11/12/2011. (3) Factorial number system, http://en.wikipedia.org/wiki/Factorial_number_system - acessado em

11/12/2011.

(4) permutação, http://en.wikipedia.org/wiki/permutação - acessado em 11/12/2011. (5) Enumerating permutation using inversion vectors and factoradic numbering, http://lin-ear-th- inking.blogspot.com/2012/11/enumerating-permutaçãos-using.html - . acessado em

11/12/2011.