Delphi 中的不同排列子集秩和非秩
Distinct permutation subset rank and unrank in Delphi
你好Delphi堆垛机。
我搜索了整个站点,所有 "permutation rank & unrank" 相关讨论,但找不到满足我需要的那个。
在Delphi中:
有一个数组:
Members: array [0..3] of Byte = (0,1,2,3);
如果要遍历由 3 个元素组成的所有不同排列,可以估计结果列表将由 24 行组成,按字典顺序排列为:
0 012
1 013
2 021
3 023
4 031
5 032
6 102
7 103
8 120
9 123
10 130
11 132
12 201
13 203
14 210
15 213
16 230
17 231
18 301
19 302
20 310
21 312
22 320
23 321
可以使用"n choose k"公式计算列表的大小,其中"n"代表成员数量,"k"代表选择数量:
p(n,k) = n! / (n-k)!
p(4,3) = 4! / (4-3)! = (4 x 3 x 2 x 1) / (1 x 1) = 24
我想弄清楚的是如何(无需搜索整个列表):
通过提供词典排名,假设“13”,可以"unrank"并获得子集“203”。
通过提供子集“203”,可以获得词典排名“13”。
任何帮助将不胜感激。
感谢您的宝贵时间。
此组合对象在俄语和法语组合学 A(n, k)
中具有特殊名称,表示 "arrangement"。不难看出,每个数字都占据排列表首位A(n-1, k-1)
次。所以我们可以找到给定排名的第一个数字,反之亦然 - 有了第一个数字,我们可以找到排名区间。然后继续下一个数字,从列表中删除使用过的数字。
function ArrangementByRank(n, k, rank: Integer): string;
function NumArrNK(n, k: Integer): Int64;
var
i: Integer;
begin
Result := 1;
for i := 0 to k - 1 do
Result := Result * (n - i);
end;
var
Dig: array of Byte;
i, j, id, ank: Integer;
begin
Result := '';
SetLength(Dig, n);
for i := 0 to n - 1 do
Dig[i] := i; //initial digit list
for i := 1 to k do begin
ank := NumArrNK(n - i, k - i); //might be optimized
id := rank div ank;
rank := rank mod ank; //prepare for the next round
Result := Result + IntToStr(Dig[id]);
for j := id to n - i - 1 do
Dig[j] := Dig[j + 1]; //squeeze digit list
end;
end;
调用参数 5, 3, 15
returns 安排 1,2,0
。对于反向任务排名可能发现为
(Index of 1 in initial list) * A(4,2) + (Index of 2 in squeezed list) * A(3,1) =
1 * A(4,2) + 1 * A(3,1) =
12 + 3 =
15
你好Delphi堆垛机。
我搜索了整个站点,所有 "permutation rank & unrank" 相关讨论,但找不到满足我需要的那个。
在Delphi中:
有一个数组:
Members: array [0..3] of Byte = (0,1,2,3);
如果要遍历由 3 个元素组成的所有不同排列,可以估计结果列表将由 24 行组成,按字典顺序排列为:
0 012
1 013
2 021
3 023
4 031
5 032
6 102
7 103
8 120
9 123
10 130
11 132
12 201
13 203
14 210
15 213
16 230
17 231
18 301
19 302
20 310
21 312
22 320
23 321
可以使用"n choose k"公式计算列表的大小,其中"n"代表成员数量,"k"代表选择数量:
p(n,k) = n! / (n-k)!
p(4,3) = 4! / (4-3)! = (4 x 3 x 2 x 1) / (1 x 1) = 24
我想弄清楚的是如何(无需搜索整个列表):
通过提供词典排名,假设“13”,可以"unrank"并获得子集“203”。
通过提供子集“203”,可以获得词典排名“13”。
任何帮助将不胜感激。
感谢您的宝贵时间。
此组合对象在俄语和法语组合学 A(n, k)
中具有特殊名称,表示 "arrangement"。不难看出,每个数字都占据排列表首位A(n-1, k-1)
次。所以我们可以找到给定排名的第一个数字,反之亦然 - 有了第一个数字,我们可以找到排名区间。然后继续下一个数字,从列表中删除使用过的数字。
function ArrangementByRank(n, k, rank: Integer): string;
function NumArrNK(n, k: Integer): Int64;
var
i: Integer;
begin
Result := 1;
for i := 0 to k - 1 do
Result := Result * (n - i);
end;
var
Dig: array of Byte;
i, j, id, ank: Integer;
begin
Result := '';
SetLength(Dig, n);
for i := 0 to n - 1 do
Dig[i] := i; //initial digit list
for i := 1 to k do begin
ank := NumArrNK(n - i, k - i); //might be optimized
id := rank div ank;
rank := rank mod ank; //prepare for the next round
Result := Result + IntToStr(Dig[id]);
for j := id to n - i - 1 do
Dig[j] := Dig[j + 1]; //squeeze digit list
end;
end;
调用参数 5, 3, 15
returns 安排 1,2,0
。对于反向任务排名可能发现为
(Index of 1 in initial list) * A(4,2) + (Index of 2 in squeezed list) * A(3,1) =
1 * A(4,2) + 1 * A(3,1) =
12 + 3 =
15