Основываясь на очень простом и элегантном рекурсивном решении, предложенном Адамом по другому вопросу: «Алгоритм возврата всех комбинаций k элементов из n», который вы можете найти в другом месте.
Однако ответ Адама даетдля получения всех комбинаций из заданного набора, который не совсем соответствует вопросу, на который был дан его ответ, но я обнаружил, что его ответ идеально соответствует цели моего исследования.Я ищу ценность там, где могу ее найти.И это действительно соответствует данному вопросу.
Я разработал следующую программу, используя Open Arrays в Free Pascal, для создания всех комбинаций элементов в любом данном массиве.Открытый массив допускает произвольное и динамически переменное количество элементов, и каждый элемент может быть любым типом переменной или записи.Эта программа имеет элементы с длинными целыми числами, но может также использоваться для указателей на другие переменные.Я использовал его таким образом, чтобы определить наиболее эффективный способ разрезания металлических стержней на различные длины более коротких стержней, изучая различные возможные комбинации более коротких стержней различной длины, которые подходят к исходным стержням.
Процедуракомбо повторяется один раз для каждой возможной комбинации, но глубина рекурсии всего на один уровень больше, чем количество элементов в «ожидающем» исходном массиве.Передача параметров в комбинированную процедуру по ссылке не обязательна, но это сокращает требования к оперативной памяти почти вдвое.
program combinata;
uses
SYSUTILS;
type
combarry = array of longint;
var
testc, testp :combarry;
procedure produce (var cmb :combarry);
var x :integer;
begin
for x := 0 to length(cmb)-1 do begin
if x > 0 then write(',');
write(cmb[x]:0);
end;
writeln;
end;
procedure combo (var current, pending :combarry);
var
x, len :integer;
newcurrent, newpending :combarry;
begin
if length(pending) = 0 then
if length(current) > 0 then produce(current) else
else begin
{append 1st element of pending as the last element on current}
newcurrent := current;
len := length(newcurrent);
setlength(newcurrent,len+1);
newcurrent[len] := pending[0];
{remove the first element from pending}
len := length(pending) - 1;
setlength(newpending,len);
for x := len downto 1 do newpending[x-1] := pending[x];
combo(newcurrent,newpending);
combo(current,newpending);
end;
end;
begin
setlength(testc,0);
setlength(testp,4);
testp[0] := 5;
testp[1] := 10;
testp[2] := 15;
testp[3] := 20;
combo(testc, testp);
writeln('*');
end.
Running this produces:
5,10,15,20
5,10,15
5,10,20
5,10
5,15,20
5,15
5,20
5
10,15,20
10,15
10,20
10
15,20
15
20
*