Excelでカッティングストック問題

# 問題の入力部分の表を作ります。

仕事であるNC旋盤でリアルにカッティングストック問題を製造計画に利用しています。
テーブルK01A_は、カッティングストック問題の入力部分を定義しています。
一本のパイプ材から、長さの違う最大４パターンの製品を切り出す仕様になっています。
テーブルの上段のA,B,C,Dは、切り出す長さに、Lはパイプ材の有効長になります。
テーブルの下段のA,B,C,Dは、各々を切り出すパターン数、L=900=9*10*10*1 となります。

![K01.png](https://qiita-image-store.s3.amazonaws.com/0/184069/c1fbcdb9-f11b-f06b-5ccc-75a7e1dcfca3.png)

テーブルK01_Jの内容は、計算を簡単にするためパターンをP,Qで絞り込んでいます。
P=余材が少ないパターンから計算の対象にするパターン数
Q=カッティングする長さの最小長
JC=P,Qから計算される余材の最大長

```vb
(K01J_[JC])  =JC(K01A_,[P],[Q])    [15]

Function JC(R, Optional P = 12, Optional Q = 166, Optional S = "")
    Dim A, B, C, D, L, L1
    Dim NA, NB, NC, ND, N
    
    Call DR(R, 1, A, B, C, D, L)
    Call DR(R, 2, NA, NB, NC, ND, N)
    
    Dim U: U = CC(NA, " ", NB, " ", NC, " ", ND)
    Dim Y: Y = Array(A, B, C, D)
    
  
    Dim I: For I = 1 To N - 1
        L1 = L - WorksheetFunction.SumProduct(GP(I, NA, NB, NC, ND), Y) ' GENERATE PATTERN
        If 0 <= L1 And L1 < Q Then S = CC(S, L1, " ")
    Next I
    Dim T: T = V_(S)
    If UBound(T) < P Then
        S = WorksheetFunction.MAX(T)
    Else
        S = WorksheetFunction.Small(T, P)
    End If
    
    JC = S
End Function
```

# カッティングパターンの生成を行います。


![BT.png](https://qiita-image-store.s3.amazonaws.com/0/184069/56652516-2438-c61b-198d-e9c0a64886db.png)


```vb
(K01B_[P])   =JP(K01A_,[P],K01J_[JC])      [603 522 351 270]
(K01B_残材)   =JZ(K01A_,[@P])
(K01B_I)     =JI([@P],K01A_,1)
(K01B_J)     =JI([@P],K01A_,2)
(K01B_K)     =JI([@P],K01A_,3)
(K01B_L)     =JI([@P],K01A_,4)
(K01B_U)     =JU([M])

Function JP(R1, R2, Optional E = 166, Optional S = "") ' (K01B_[P]) =JP(K01A_,[P],K01J_[JC])
    On Error Resume Next
    
    Dim M: M = MM(R2)
    Dim A, B, C, D, NA, NB, NC, ND, K, X, L0, L, J
    
    Call DR(R1, 1, A, B, C, D, L)
    Call DR(R1, 2, NA, NB, NC, ND, K)
    
    If M = 1 Then
        J = K - 1
    ElseIf DI(R2, M - 1) = "" Then
        J = 0
    Else
        J = DI(R2, M - 1) - 1
    End If
    
    Dim I: For I = J To 1 Step -1
        L0 = L - WorksheetFunction.SumProduct(Array(A, B, C, D), GP(I, NA, NB, NC, ND))

        If 0 <= L0 And L0 <= E Then
            S = I
            Exit For
        End If
    Next I
    JP = S
End Function

Function GP(P, ParamArray A()) ' Generate Pattern
    Dim S: S = ""
    Dim E: E = P
    Dim I: For I = UBound(A) To 0 Step -1
        S = CC(E Mod A(I), " ", S)
        E = Int(E / A(I))
    Next I
    S = V_(S)
    GP = S
End Function

Function JZ(R, P, Optional S = "")  ' (K01B_[残材])
    On Error Resume Next

    Dim A, B, C, D, L, NA, NB, NC, ND

    If P > 0 Then
        Dim I: I = P
        Call DR(R, 1, A, B, C, D, L)
        Call DR(R, 2, NA, NB, NC, ND)

        S = L - WorksheetFunction.SumProduct(Array(A, B, C, D), GP(I, NA, NB, NC, ND))
    End If
    JZ = S
End Function

Function JI(I, R, M, Optional S = 0)
    If I <> "" Then
       Dim NA, NB, NC, ND
   
       Call DR(R, 2, NA, NB, NC, ND)
    
       If M = 1 And NA > 1 Then S = Int(I / (NB * NC * ND))
       If M = 2 And NB > 1 Then S = Int(I / (NC * ND)) Mod NB
       If M = 3 And NC > 1 Then S = Int(I / ND) Mod NC
       If M = 4 And ND > 1 Then S = I Mod ND
    End If
    JI = IFZS(S)
End Function

Function JU(R, Optional S = "")   ' (K01B_[U])
    Dim M: M = MM(R)
    If DI(R, M) > 0 Then S = WorksheetFunction.CountIf(R.Resize(M), CC(">0"))
    JU = S
End Function
```

# ソルバーを設定します。


解決を押すと、変数セルの変更に解答が表示されます。

![SOLVER.png](https://qiita-image-store.s3.amazonaws.com/0/184069/ef499fc7-4607-bb49-ffb2-2a2887bd5588.png)