列举所有组合(笛卡尔积,算盘,里程表)

时间:2013-04-10 04:51:18

标签: algorithm delphi combinatorics

如何以下列方式在Delphi(Object Pascal)中实现以下算法:

  • 每个字母数字项都是单个对象(在我的例子中是对文件字符串的引用)。
  • 可以枚举(输出)每个选择状态/组合。
  • 想象一下算盘的列;都具有相同的大小(根据其基数)。我需要不同大小的列。 (在我的例子中,具有不同大小的文件串集)

上次编辑:请参阅Python intertools implementation

其他语言的类似算法:c#rubyjavaphp

算法

考虑以下几组及其成员:

  

S1 = {a1,a2,a3,a4,a5}

     

S2 = {b1,b2,b3,b4}

     

S3 = {c1,c2,c3,c4,c5}

选择每组中的第一个成员(P =选择状态):

  

P1 = {a1,b1,c1}

然后,将第一个增加到其限制:

  

P2 = {a2,b1,c1} P3 = {a3,b1,c1} P4 = {a4,b1,c1} P5 = {a5,b1,   C1}

然后,重置第一组,并将第二组增加“1”;

  

P6 = {a1,b2,c1}

再次增加第一组...依此类推......重置第三组中每个'加一'的第一组和第二组。

  

P7 = {a2,b2,c1}

关于计数的基本原理或乘法原理,该算法将生成100个拾取状态/组合。

  

P100 = {a5,b4,c5}

2 个答案:

答案 0 :(得分:1)

你在数。

每个珠子都是一个数字,你在你的例子中你在5号基地工作,因为每个珠子可以有5个位置中的一个。

要确定珠子的哪个位置对应于给定的整数,在相关基数中写入该整数就足够了。以下是17

中的ruby方法
>> 17.to_s(5).rjust(3, '0')
=> "032"

在这里,我将左边填充到3个珠子,以清楚每个珠子的位置,并且我正在使用珠子从位置0开始而不是位置1的约定。

答案 1 :(得分:1)

我使用递归和条件调用达到了解决方案。我用这种结构创建了一条记录:

  TGridKey = record
    ID : Integer;
    Index : Integer;
    Files : TStringList;
  end;

  TTrialSet = record
    theGrid : array of TGridKey;
  end;

在TForm类中使用此名称。

TfRandStimuliSet = class (TForm)

    //...
    lst1: TListBox; 
    dlgOpenPic: TOpenPictureDialog;
private        
    FTrialSet: TTrialSet;
    procedure TfRandStimuliSet.SubSetsMountEngine;
    //...
end;

设置网格阵列的长度:

  NumComp := 3;
  SetLength(FTrialSet.theGrid, NumComp);
  for I := Low(FTrialSet.theGrid) to High(FTrialSet.theGrid) do
  begin
    FTrialSet.theGrid[I].ID := I;
    FTrialSet.theGrid[I].Index:= -1;
    FTrialSet.theGrid[I].Files := TStringList.Create;
  end;

在每个'I'网格中添加一些字符串:

if dlgOpenPic.Execute then
  begin
    if dlgOpenPic.Files.Count > 0 then
    for K := 0 to (dlgOpenPic.Files.Count - 1) do
    begin
     FTrialSet.theGrid[I].Files.Add(dlgOpenPic.Files.Strings[K]);
    end;
    dlgOpenPic.Files.Clear;
  end;

然后程序:

procedure TfRandStimuliSet.SubSetsMountEngine;
var ID: integer; s1 : string;
  procedure AddStmFromGrid(Grid, Stm : Integer);
  begin
    s1 := s1 + ExtractFileName(FTrialSet.theGrid[Grid].Files.Strings[Stm]) + ',';
  end;

  procedure AddTrialFromIndex; //each trial is the current index's
  var I: Integer;
  begin

    for I:= Low(FTrialSet.theGrid) to High(FTrialSet.theGrid) do
      AddStmFromGrid(I,FTrialSet.theGrid[I].Index);
    lst1.Items.Add(s1);
    s1:= '';
  end;

  procedure IndexReset(aGrid : Integer);
  var i : Integer;
  begin
    for  I := aGrid to (High(FTrialSet.theGrid)) do
      FTrialSet.theGrid[I].Index := 0
  end;

  procedure IndexInc(aGrid : Integer);
  begin
    AddTrialFromIndex; //Save
    Inc(FTrialSet.theGrid[aGrid].Index);
  end;

      function MoveGrid(var ID:integer): Boolean;   //begin from right most, the highest grid
      var IDMaxIndex, IDCurIndex, LowID, HighID: Integer;
      begin
        Result := True;
        LowID := Low(FTrialSet.theGrid);
        HighID := High(FTrialSet.theGrid);
        //Application.ProcessMessages;
        if  (ID < LowID) then 
          begin
            //ShowMessage('False');
            AddTrialFromIndex;
            Result := False;
          end
        else
          begin
            IDMaxIndex:= FTrialSet.theGrid[ID].Files.Count -1;
            IDCurIndex := FTrialSet.theGrid[ID].Index;

            if IDCurIndex = IDMaxIndex then  
              begin
                ID := ID - 1;
                Result:= MoveGrid(ID);//moveleft
                Exit;
              end;
            if   (ID < HighID)
             and (IDCurIndex < IDMaxIndex) then 
              begin
                IndexInc(ID);                 //increment/move donw
                IndexReset(ID + 1);           //reset everything on the right
                MoveGrid(HighID);             //move to the most right/next down
                Exit;
              end;
            if  (ID = (HighID))
             and (IDCurIndex < IDMaxIndex) then
              begin
                IndexInc(ID);          //increment/move down 
                MoveGrid(ID)           //next increment/move down
              end;  
          end;
      end;
begin
  ID := High(FTrialSet.theGrid);
  IndexReset(Low(FTrialSet.theGrid));  //0's for everyone
  MoveGrid(ID); //begin from the most right
end;