Search code examples
algorithmhaskellmathnumber-theoryinteger-partition

Number of Integer Composition with the number which is in a specific list


Each positive integer n has 2^(n−1) distinct compositions. what If I want the number of composition which is only have specific number which is in my list:

for example composition of 4 is

4
3 1
1 3
2 2
2 1 1
1 2 1
1 1 2
1 1 1 1

but if I want the number of composition of 4 which it has only 1 and 2, How could I calculate the NUMBER of distinct compositions?

2 2
2 1 1
1 2 1
1 1 2
1 1 1 1

Edited: Here Haskell code which calculate the number, But I think It takes too long even IF I add memorization for Number 70

main :: IO ()
main = do
     putStrLn "Enter the integer number"
     num' <- getLine
     let num = read num' :: Int
     putStr ""
     let result= composition num
     let len=length result
     print len
      --print result

composition 0 = [[]]
composition n = [x:rest | x <- [1,2,3,4,5,6,7,8,9,10,20,30,40,50,60,70,80,90,100,200,300,400,500,600,700,800,900,1000],x<=n ,rest <- composition (n-x)]

Solution

  • You can use dynamic programming to calculate the number of needed compositions. Example of recursive relation for your example:

     P(4, [1,2]) = P(3, [1,2])  + P(2, [1,2])
    

    here P(N, [list]) is the number of variants to make N from the list

    Try to generalize formulas and use top-down memoization or bottom-up table filling DP to quickly find the result.

    Delphi example:

    var
      A: TArray<Integer>;
      Mem: TArray<Int64>;
      N, i: Integer;
    
      function Calc(N: Integer): Int64;
      var
        i: Integer;
      begin
        if Mem[N] >= 0 then
          Exit(Mem[N]);
    
        i := 0;
        Result := 0;
        while A[i] <= N do begin
          Result := Result + Calc(N - A[i]);
          Inc(i);
        end;
        Mem[N] := Result;
      end;
    
    begin
      //should be sorted
      //-1 - sentinel value to stop
      A := TArray<Integer>.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60,
        70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, -1);
      for N := 10 to 64 do begin
        SetLength(Mem, N + 1);
        for i := 1 to N do
          Mem[i] := -1; //not initialized yet
        Mem[0] := 1;
        Memo1.Lines.Add(Format('%d   %d', [N, Calc(N)]));
      end;