Permutations: Difference between revisions
Content added Content deleted
(Added solution for EDSAC.) |
(Added a third Pascal solution (permutations from integers)) |
||
Line 6,928: | Line 6,928: | ||
479001600 //= 12! |
479001600 //= 12! |
||
00:00:01.328</pre> |
00:00:01.328</pre> |
||
===Permutations from integers=== |
|||
A console application in Free Pascal, created with the Lazarus IDE. |
|||
<lang pascal> |
|||
program Permutations; |
|||
(* |
|||
Demonstrates four closely related ways of establishing a bijection between |
|||
permutations of 0..(n-1) and integers 0..(n! - 1). |
|||
Each integer in that range is represented by mixed-base digits d[0..n-1], |
|||
where each d[j] satisfies 0 <= d[j] <=j. |
|||
The integer represented by d[0..n-1] is |
|||
d[n-1]*(n-1)! + d[n-2]*(n-2)! + ... + d[1]*1! + d[0]*0! |
|||
where the last term can be omitted in practice because d[0] is always 0. |
|||
See the section "Numbering permutations" in the Wikipedia article |
|||
"Permutation" (NB their digit array d is 1-based). |
|||
*) |
|||
uses SysUtils, TypInfo; |
|||
type TPermIntMapping = (map_I, map_J, map_K, map_L); |
|||
type TPermutation = array of integer; |
|||
// Function to map an integer to a permutation. |
|||
function IntToPerm( map : TPermIntMapping; |
|||
nrItems, z : integer) : TPermutation; |
|||
var |
|||
d, lookup : array of integer; |
|||
x, y : integer; |
|||
h, j, k, m : integer; |
|||
begin |
|||
SetLength( result, nrItems); |
|||
SetLength( lookup, nrItems); |
|||
SetLength( d, nrItems); |
|||
m := nrItems - 1; |
|||
// Convert z to digits d[0..m] (see comment at head of program). |
|||
d[0] := 0; |
|||
y := z; |
|||
for j := 1 to m - 1 do begin |
|||
x := y div (j + 1); |
|||
d[j] := y - x*(j + 1); |
|||
y := x; |
|||
end; |
|||
d[m] := y; |
|||
// Set up the permutation elements |
|||
case map of |
|||
map_I, map_L: for j := 0 to m do lookup[j] := j; |
|||
map_J, map_K: for j := 0 to m do lookup[j] := m - j; |
|||
end; |
|||
for j := m downto 0 do begin |
|||
k := d[j]; |
|||
case map of |
|||
map_I: result[lookup[k]] := m - j; |
|||
map_J: result[j] := lookup[k]; |
|||
map_K: result[lookup[k]] := j; |
|||
map_L: result[m - j] := lookup[k]; |
|||
end; |
|||
// When lookup[k] has been used, it's removed from the lookup table |
|||
// and the elements above it are moved down one place. |
|||
for h := k to j - 1 do lookup[h] := lookup[h + 1]; |
|||
end; |
|||
end; |
|||
// Function to map a permutation to an integer; inverse of the above. |
|||
// Put in for completeness, not required for Rosetta Code task. |
|||
function PermToInt( map : TPermIntMapping; |
|||
p : TPermutation) : integer; |
|||
var |
|||
m, i, j, k : integer; |
|||
d : array of integer; |
|||
begin |
|||
m := High(p); // number of items in permutation is m + 1 |
|||
SetLength( d, m + 1); |
|||
for k := 0 to m do d[k] := 0; // initialize all digits to 0 |
|||
// Looking for inversions |
|||
for i := 0 to m - 1 do begin |
|||
for j := i + 1 to m do begin |
|||
if p[j] < p[i] then begin |
|||
case map of |
|||
map_I : inc( d[m - p[j]]); |
|||
map_J : inc( d[j]); |
|||
map_K : inc( d[p[i]]); |
|||
map_L : inc( d[m - i]); |
|||
end; |
|||
end; |
|||
end; |
|||
end; |
|||
// Get result from its digits (see comment at head of program). |
|||
result := d[m]; |
|||
for j := m downto 2 do result := result*j + d[j - 1]; |
|||
end; |
|||
// Main routine to generate permutations of the integers 0..(n-1), |
|||
// where n is passed as a command-line parameter, e.g. Permutations 4 |
|||
var |
|||
n, n_fac, z, j : integer; |
|||
nrErrors : integer; |
|||
perm : TPermutation; |
|||
map : TPermIntMapping; |
|||
lineOut : string; |
|||
pinfo : TypInfo.PTypeInfo; |
|||
begin |
|||
n := SysUtils.StrToInt( ParamStr(1)); |
|||
n_fac := 1; |
|||
for j := 2 to n do n_fac := n_fac*j; |
|||
pinfo := System.TypeInfo( TPermIntMapping); |
|||
lineOut := 'integer'; |
|||
for map := Low( TPermIntMapping) to High( TPermIntMapping) do begin |
|||
lineOut := lineOut + ' ' + TypInfo.GetEnumName( pinfo, ord(map)); |
|||
end; |
|||
WriteLn( lineOut); |
|||
for z := 0 to n_fac - 1 do begin |
|||
lineOut := SysUtils.Format( '%7d', [z]); |
|||
for map := Low( TPermIntMapping) to High( TPermIntMapping) do begin |
|||
perm := IntToPerm( map, n, z); |
|||
// Check the inverse mapping (not required for Rosetta Code task) |
|||
Assert( z = PermToInt( map, perm)); |
|||
lineOut := lineOut + ' '; |
|||
for j := 0 to n - 1 do |
|||
lineOut := lineOut + SysUtils.Format( '%d', [perm[j]]); |
|||
end; |
|||
WriteLn( lineOut); |
|||
end; |
|||
end. |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
integer map_I map_J map_K map_L |
|||
0 0123 0123 0123 0123 |
|||
1 0132 1023 1023 0132 |
|||
2 0213 0213 0213 0213 |
|||
3 0312 2013 1203 0231 |
|||
4 0231 1203 2013 0312 |
|||
5 0321 2103 2103 0321 |
|||
6 1023 0132 0132 1023 |
|||
7 1032 1032 1032 1032 |
|||
8 2013 0312 0231 1203 |
|||
9 3012 3012 1230 1230 |
|||
10 2031 1302 2031 1302 |
|||
11 3021 3102 2130 1320 |
|||
12 1203 0231 0312 2013 |
|||
13 1302 2031 1302 2031 |
|||
14 2103 0321 0321 2103 |
|||
15 3102 3021 1320 2130 |
|||
16 2301 2301 2301 2301 |
|||
17 3201 3201 2310 2310 |
|||
18 1230 1230 3012 3012 |
|||
19 1320 2130 3102 3021 |
|||
20 2130 1320 3021 3102 |
|||
21 3120 3120 3120 3120 |
|||
22 2310 2310 3201 3201 |
|||
23 3210 3210 3210 3210 |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |