1次元Bin Packingアルゴリズムを活用した作業配分の最適化_4。
この記事のソースコードは、Bin Packingツールの最初のバージョンベースで書かれています。機能が改善された最新バージョンがあるので、一緒に参照してください。
1次元Bin Packingツール最近の変更(2021-03-21基準)
5. 別添
5.1。 Excel VBAベースのツールソースコード
Excel VBAで実装されたBin Packingは、外部ライブラリやパッケージなしで純粋にVBAコードでのみ実装され、ソースコードの量が長い方だ。アルゴリズムの多くはCPackerクラスに実装されているので、最初にこのクラスを見てください。
5.1.1。 Run sheet ソースコード
「Run BinPacking」ボタンのクリックイベントに対応するコードです。
ExcelのRangeオブジェクトを使用して、リストのベース範囲とオプション値をRunBinPackingプロシージャに渡します。ここで、Rangeは名称で定義された個体を主に使用した。 (例:Range(“MaxBinSize”))Rangeを名前で定義すると、参照アドレスが変更されてもソースコードを変更する必要がなく、特に行挿入、列挿入などの機能が実行されるときに参照アドレスが自動的に変更され便利です。 。
Private Sub cmdRunBinPacking_Click() RunBinPacking aBaseRange:=Range("B2").Address, _ aMaxBinSize:=Range("MaxBinSize").Value, _ aSizeBaseColumn:=Range("SizeBaseClolumn").Value, _ aIsItemSort:=Range("ItemSize내림차순정렬여부").Value End Sub
5.1.2。 modFactoryモジュールのソースコード
クラスのインスタンスを生成する役割を担う。 VBAのクラスは、パラメータを持つコンストラクタのオーバーライドを行うことはできません。 Factory Patternで実装したモジュールをコンストラクタの代わりに使用する。
CreatePackerプロシージャのaPackingTypeは、Bin Packingアルゴリズムの処理タイプを表す列挙変数です。可能な値は ptNextFit、ptFirstFit、ptBestFit、ptWorstFit の 4 つです。
Option Explicit Public Function CreatePacker(aMaxBinSize As Long, aPackingType As PackingType) As CPacker Set CreatePacker = New CPacker CreatePacker.Init aMaxBinSize, aPackingType End Function Public Function CreateBin(aMaxBinSize As Long) As CBin Set CreateBin = New CBin CreateBin.Init aMaxBinSize End Function
5.1.3。 modControlモジュールのソースコード
RunBinPackingプロシージャでアルゴリズム全体の処理プロセスを管理する役割を担います。パラメータそれぞれの意味は次のとおりです。
- aBaseRange:入力データの開始範囲(「B2」などの文字列)
- aMaxBinSize: 1 ビンの最大サイズ制約 (80、10000 などの整数)
- aSizeBaseColumn:オプションで選択したBinサイズベースの列名(「C」などの文字列)
- aIsItemSort:降順ソートを実行するかどうか(True / False値)
Option Explicit Public Sub RunBinPacking(aBaseRange As String, aMaxBinSize As Long, _ aSizeBaseColumn As String, aIsItemSort As Boolean) Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Dim oBaseRange As Range, lCurRow As Long, oBinItem As CBinItem Dim oInputItemCol As CBinItemCollection: Set oInputItemCol = New CBinItemCollection Set oBaseRange = Range(aBaseRange) Dim sSizeBaseColumn As String, lSizeColumnOffset As Long sSizeBaseColumn = aSizeBaseColumn 'Range("SizeBaseClolumn") lSizeColumnOffset = Range(oBaseRange, sSizeBaseColumn & "2").Columns.Count - 1 'Build up the BinItem List Collection lCurRow = 0 For lCurRow = 0 To oBaseRange.CurrentRegion.Rows.Count If Trim(oBaseRange.Offset(lCurRow, 0).Value) = "" Then Exit For Set oBinItem = New CBinItem oBinItem.m_sName = oBaseRange.Offset(lCurRow, 0).Value 'Item Name oBinItem.m_lSize = oBaseRange.Offset(lCurRow, lSizeColumnOffset).Value 'Item Size 기준 컬럼의 값(예: KB, MB 등) oInputItemCol.Add oBinItem, oBinItem.m_sName Next lCurRow 'Item Size로 내림차순 정렬 처리 If aIsItemSort Then DoLog "정렬 전 --> " + oInputItemCol.GetString Set oInputItemCol = oInputItemCol.Sort DoLog "정렬 후 --> " + oInputItemCol.GetString End If Dim lMaxBinSize As Long Dim oPackerNextFit As CPacker, oPackerFirstFit As CPacker Dim oPackerWorstFit As CPacker, oPackerBestFit As CPacker lMaxBinSize = aMaxBinSize 'NextFit Set oPackerNextFit = CreatePacker(lMaxBinSize, ptNextFit) oPackerNextFit.DoPacking oInputItemCol oPackerNextFit.DoOutput Worksheets("Next Fit") Set oPackerNextFit = Nothing 'FirstFit Set oPackerFirstFit = CreatePacker(lMaxBinSize, ptFirstFit) oPackerFirstFit.DoPacking oInputItemCol oPackerFirstFit.DoOutput Worksheets("First Fit") Set oPackerFirstFit = Nothing 'WorstFit Set oPackerWorstFit = CreatePacker(lMaxBinSize, ptWorstFit) oPackerWorstFit.DoPacking oInputItemCol oPackerWorstFit.DoOutput Worksheets("Worst Fit") Set oPackerWorstFit = Nothing 'BestFit Set oPackerBestFit = CreatePacker(lMaxBinSize, ptBestFit) oPackerBestFit.DoPacking oInputItemCol oPackerBestFit.DoOutput Worksheets("Best Fit") Set oPackerBestFit = Nothing Worksheets("Result Summary").Activate Worksheets("Result Summary").Range("E1") = lMaxBinSize DoEvents Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub
5.1.4。 modUtilモジュールのソースコード
Logging、所要時間を文字列形式に変換するなどの共通機能を担当する。 LoggingはWindows API OutputDebugStringを利用する。
Option Explicit #Const DEBUGMODE = 1 #If VBA7 Then 'For 64 Bit Systems Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr) Private Declare PtrSafe Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal lpOutputString As String) #Else 'For 32 Bit Systems Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Declare Sub OutputDebugString Lib "kernel32" Alias "OutputDebugStringA" (ByVal lpOutputString As String) #End If 'OutputDebugString API를 이용한 Debug Message 출력 'DebugView등을 이용하여 메시지 View 가능함 Public Sub DoLog(aMsg As String) #If DEBUGMODE >= 1 Then OutputDebugString "[Bin] " & aMsg #End If End Sub Function GetTimeString(dTime As Double) As String Dim H As Integer, M As Integer, S As Integer, MS As Integer, dMS As Double, sMS As String H = Int(dTime / 3600) M = Int(dTime / 60) Mod 60 S = Int(dTime Mod 60) dMS = (dTime - Int(dTime)) 'MS = dMS * 10 ^ (Len(CStr(dMS)) - 2) sMS = Mid(CStr(dMS), 3, Len(dMS)) GetTimeString = Format(H, "00") & ":" & Format(M, "00") & ":" & Format(S, "00") & "." & sMS End Function
5.1.5。 CPackerクラスのソースコード
入力データを既存のBinリストの適切な場所に埋めるか、新しいBinを作成して埋めるBin Packingアルゴリズムを実装します。主な変数、プロシージャ、関数は次のとおりです。
- Binオブジェクトのリストをm_oBinColコレクション変数として管理し、各Binオブジェクトの残りの合計をlRemainSizeSum変数として管理します。
- Initプロシージャ:Binの最大サイズと塗りつぶすアルゴリズムの種類(Next Fit、First Fit、Best Fit、Worst Fit)を設定します。
Add プロシージャ: パラメータとして渡された Bin オブジェクトを m_oBinCol collection 変数に追加し、名前を「Bin_順番 5 桁」として生成します。 - DoPackingプロシージャ:パラメータとして渡されたItemリストをBinオブジェクトのリストに入力します。
- GetNewBin関数:modFactoryモジュールのCrreateBin関数を使用して新しいBinオブジェクトを作成します。
- GetBinNextFit関数:パラメータとして渡されたBinItemをNext Fitアルゴリズムで埋める適切なBinを選択するか、新しく作成して返します。
- GetBinFirstFit関数:パラメータとして渡されたBinItemをFirst Fitアルゴリズムで埋める適切なBinを選択するか、新しく作成して返します。
- GetBinWorstFit関数:パラメータとして渡されたBinItemをWorst Fitアルゴリズムで埋める適切なBinを選択するか、新しく生成して返します。
- GetBinBestFit関数:パラメータとして渡されたBinItemをBest Fitアルゴリズムで埋める適切なBinを選択するか、新しく生成して返します。
- PackToBinプロシージャ:設定したアルゴリズムの種類に応じて適切な関数を呼び出してBinItemを埋めます。
- DoOutput プロシージャ: Bin Packing 処理結果を指定したシートに出力する。
Option Explicit Public m_oBinCol As Collection Public m_dElapsedTime As Double Public Enum PackingType ptNextFit ptFirstFit ptBestFit ptWorstFit End Enum Private m_lMaxBinSize As Long Private m_lLastBinIndex As Long Private m_PackingType As PackingType Private m_lCompareCount As Long '비교연산의 횟수 누적 Private m_lRemainSizeSum As Long '잔여공간 합계 Private m_oTimer As CTimer Private Sub Class_Initialize() Set m_oBinCol = New Collection Set m_oTimer = New CTimer m_lLastBinIndex = 1 m_lCompareCount = 0 End Sub Private Sub Class_Terminate() Set m_oBinCol = Nothing Set m_oTimer = Nothing End Sub Public Sub Init(aMaxBinSize As Long, aPackingType As PackingType) m_lMaxBinSize = aMaxBinSize m_PackingType = aPackingType End Sub '입력자료 목록을 입력으로 전체 채우기 실행 Public Sub DoPacking(aInputItemCol As CBinItemCollection) Dim oBinItem As CBinItem m_oTimer.StartCounter For Each oBinItem In aInputItemCol.m_oBinItemCol Me.PackToBin oBinItem Next Me.m_dElapsedTime = m_oTimer.TimeElapsed End Sub '한 Item 채우기 Public Sub PackToBin(oBinItem As CBinItem) Dim oBin As CBin 'Select Case ePackingType Select Case m_PackingType Case ptNextFit Set oBin = GetBinNextFit(oBinItem) Case ptFirstFit Set oBin = GetBinFirstFit(oBinItem) Case ptWorstFit Set oBin = GetBinWorstFit(oBinItem) Case ptBestFit Set oBin = GetBinBestFit(oBinItem) End Select oBin.AddBinItem oBinItem End Sub Public Sub Add(oBin As CBin) m_oBinCol.Add oBin oBin.m_lIndex = m_oBinCol.Count 'oBin.m_sName = "Bin" + CStr(m_oBinCol.Count) oBin.m_sName = "Bin_" + Format(CStr(m_oBinCol.Count), "00000") End Sub Public Function GetNewBin() As CBin Dim oBin As CBin 'Set oBin = New CBin Set oBin = CreateBin(m_lMaxBinSize) Me.Add oBin Set GetNewBin = oBin End Function 'NextFit Public Function GetBinNextFit(oBinItem As CBinItem) As CBin Dim oBin As CBin, oResult As CBin If m_oBinCol.Count = 0 Then '첫번째 실행인 경우 Set oResult = GetNewBin m_lLastBinIndex = 1 Else Set oBin = m_oBinCol(m_lLastBinIndex) m_lCompareCount = m_lCompareCount + 1 If oBin.IsAbleToAdd(oBinItem) Then Set oResult = oBin Else Set oResult = GetNewBin m_lLastBinIndex = oResult.m_lIndex End If End If Set GetBinNextFit = oResult End Function 'FirstFit Public Function GetBinFirstFit(oBinItem As CBinItem) As CBin Dim oBin As CBin, bFound As Boolean, lCurBinIndex As Long, oResult As CBin bFound = False '항상 처음 Bin부터 확인하여 추가할 수 있는 Bin return For lCurBinIndex = 1 To m_oBinCol.Count 'For Each oBin In m_oBinCol Set oBin = m_oBinCol(lCurBinIndex) m_lCompareCount = m_lCompareCount + 1 If oBin.IsAbleToAdd(oBinItem) Then bFound = True Set oResult = oBin Exit For End If Next If Not bFound Then Set oResult = GetNewBin End If Set GetBinFirstFit = oResult End Function 'WorstFit Public Function GetBinWorstFit(oBinItem As CBinItem) As CBin Dim oBin As CBin, bFound As Boolean, lCurBinIndex As Long, oResult As CBin Dim lMaxRemainSize As Long, lMaxRemainSizeBinIndex As Long lMaxRemainSize = 0: lMaxRemainSizeBinIndex = 0 '모든 Bin중에서 남은 Size가 가장 크고 oBinItem을 추가할 수 있는 Bin을 return '추가할 수 있는 Bin이 없으면 새 Bin을 생성 For lCurBinIndex = 1 To m_oBinCol.Count '남은 Size가 가장 큰 Bin 찾기 Set oBin = m_oBinCol(lCurBinIndex) m_lCompareCount = m_lCompareCount + 1 If lMaxRemainSize < oBin.m_lRemainSize Then lMaxRemainSize = oBin.m_lRemainSize lMaxRemainSizeBinIndex = lCurBinIndex End If Next bFound = False m_lCompareCount = m_lCompareCount + 1 If lMaxRemainSizeBinIndex > 0 Then Set oBin = m_oBinCol(lMaxRemainSizeBinIndex) If oBinItem.m_lSize <= oBin.m_lRemainSize Then bFound = True Set oResult = oBin End If End If If Not bFound Then Set oResult = GetNewBin End If Set GetBinWorstFit = oResult End Function 'BestFit Public Function GetBinBestFit(oBinItem As CBinItem) As CBin Dim oBin As CBin, bFound As Boolean, lCurBinIndex As Long, oResult As CBin Dim lMinRemainSize As Long, lMinRemainSizeBinIndex As Long lMinRemainSize = m_lMaxBinSize lMinRemainSizeBinIndex = 0 '모든 Bin중에서 남은 Size가 가장 적으면서 oBinItem을 추가할 수 있는 Bin을 return '추가할 수 있는 Bin이 없으면 새 Bin을 생성 For lCurBinIndex = 1 To m_oBinCol.Count 'oBinItem을 추가할 수 있는 Bin중 남은 Size가 가장 작은 Bin 찾기 Set oBin = m_oBinCol(lCurBinIndex) m_lCompareCount = m_lCompareCount + 1 If oBin.m_lRemainSize >= oBinItem.m_lSize And _ lMinRemainSize > oBin.m_lRemainSize Then lMinRemainSize = oBin.m_lRemainSize lMinRemainSizeBinIndex = lCurBinIndex End If Next bFound = False m_lCompareCount = m_lCompareCount + 1 If lMinRemainSizeBinIndex > 0 Then Set oBin = m_oBinCol(lMinRemainSizeBinIndex) bFound = True Set oResult = oBin End If If Not bFound Then Set oResult = GetNewBin End If Set GetBinBestFit = oResult End Function '결과 출력 Public Sub DoOutput(oResultSht As Worksheet) oResultSht.Activate Dim oResultBaseRange As Range, oBin As CBin, lCurRow As Long, oBinItem As CBinItem Set oResultBaseRange = oResultSht.Range("A2") 'oResultBaseRange.End(xlDown).Resize(0, 2).Clear oResultBaseRange.Select Range(Selection, Selection.End(xlDown)).Select Selection.Resize(, 3).Select 'Range(Selection, Selection.End(xlToRight)).Select Selection.ClearContents oResultBaseRange.Select lCurRow = 0 oResultSht.Range("I1") = m_dElapsedTime '소요시간 oResultSht.Range("J1").NumberFormatLocal = "@" oResultSht.Range("J1") = GetTimeString(m_dElapsedTime) oResultSht.Range("I2") = m_lCompareCount '비교횟수 oResultSht.Range("I3") = GetRemainSizeSum '잔여공간합계 oResultSht.Range("I4") = Me.m_oBinCol.Count * m_lMaxBinSize '전체공간합계 For Each oBin In Me.m_oBinCol For Each oBinItem In oBin.m_oBinItemCol.m_oBinItemCol oResultBaseRange.Offset(lCurRow, 0) = oBin.m_sName oResultBaseRange.Offset(lCurRow, 1) = oBinItem.m_sName oResultBaseRange.Offset(lCurRow, 2) = oBinItem.m_lSize lCurRow = lCurRow + 1 Next Next Dim pt As PivotTable, sDataRange As String sDataRange = oResultSht.Name + "!R1C1:R" + CStr(oResultBaseRange.CurrentRegion.Rows.Count) + _ "C" + CStr(oResultBaseRange.CurrentRegion.Columns.Count) For Each pt In oResultSht.PivotTables pt.ChangePivotCache ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=sDataRange, Version:=xlPivotTableVersion14) pt.RefreshTable Next oResultBaseRange.Select End Sub '잔여공간 합계 계산후 return Public Function GetRemainSizeSum() As Long m_lRemainSizeSum = 0 Dim oBin As CBin For Each oBin In Me.m_oBinCol m_lRemainSizeSum = m_lRemainSizeSum + oBin.m_lRemainSize Next GetRemainSizeSum = m_lRemainSizeSum End Function
5.1.6。 CBinクラスのソースコード
個々のBinを実装します。
- Bin で埋められた Item を m_oBinItemCol collection 変数で管理する。
- Initプロシージャ:Binの最大サイズを設定します。
- AddBinItemプロシージャ:itemを現在のBinに埋めるという意味でm_oBinItemColコレクションに追加します。このとき、当該Itemのサイズを現在のBinのサイズに加えてm_lCurSize変数で管理し、Binの最大サイズから現在のBinのサイズを減算して残るサイズはm_lRemainSize変数で管理する。
- IsAbleToAdd:パラメータとして渡されたBinItemを現在Binに埋めることができるかどうかを決定します。現在のBinのサイズにItemのサイズを加えた結果が最大サイズ以下であればTrueです。
Option Explicit Public m_oBinItemCol As CBinItemCollection Public m_lIndex As Long Public m_sName As String Public m_lCurSize As Long Public m_lMaxSize As Long Public m_lRemainSize As Long Private Sub Class_Initialize() Set m_oBinItemCol = New CBinItemCollection m_lCurSize = 0 End Sub Private Sub Class_Terminate() Set m_oBinItemCol = Nothing End Sub Public Sub Init(lMaxBinSize As Long) m_lMaxSize = lMaxBinSize End Sub Public Sub AddBinItem(oBinItem As CBinItem) m_oBinItemCol.Add oBinItem, oBinItem.m_sName m_lCurSize = m_lCurSize + oBinItem.m_lSize m_lRemainSize = m_lMaxSize - m_lCurSize If m_lRemainSize < 0 Then m_lRemainSize = 0 End Sub Public Function IsAbleToAdd(oBinItem As CBinItem) As Boolean IsAbleToAdd = m_lCurSize + oBinItem.m_lSize <= m_lMaxSize End Function
5.1.7。 CBinItemCollection クラスのソースコード
BinItemのリストを実装します。
- BinItemのリストをm_oBinItemCol collection変数で管理します。
- Addプロシージャ:パラメータとして渡されたItemをm_oBinItemColコレクションに追加します。
- Sort 関数: m_oBinItemCol collection を各 Item のサイズ降順にソートした新しい collection を返します。
- GetString関数:Item全体を[名前:サイズ]の形式で文字列にして返します。
Option Explicit Public m_oBinItemCol As Collection Private Sub Class_Initialize() Set m_oBinItemCol = New Collection End Sub Private Sub Class_Terminate() Set m_oBinItemCol = Nothing End Sub Public Sub Add(aBinItem As CBinItem, Optional aKey As String = "") m_oBinItemCol.Add aBinItem, IIf(aKey = "", aBinItem.m_sName, aKey) End Sub 'BinItem의 Size로 내림차순 정렬 Public Function Sort() As CBinItemCollection Dim i As Long, j As Long, k As Long, bln As Boolean Dim lngCount As Long, arr() As Long, oSortedBinItemCol As CBinItemCollection lngCount = m_oBinItemCol.Count If lngCount > 0 Then ReDim arr(0 To lngCount - 1) For i = 0 To lngCount - 1: arr(i) = i + 1: Next For i = 1 To lngCount - 1 k = arr(i) j = i - 1 bln = False Do If m_oBinItemCol(arr(j)).CompareTo(m_oBinItemCol(k)) > 0 Then arr(j + 1) = arr(j) j = j - 1 If j < 0 Then bln = True Else bln = True End If Loop Until bln arr(j + 1) = k Next End If Set oSortedBinItemCol = New CBinItemCollection For i = lngCount - 1 To 0 Step -1: oSortedBinItemCol.Add m_oBinItemCol(arr(i)): Next Set Sort = oSortedBinItemCol End Function 'BinItem 목록을 문자열로 반환 Public Function GetString() As String Dim sResult As String, oBinItem As CBinItem For Each oBinItem In m_oBinItemCol sResult = sResult + "[" + oBinItem.m_sName + ":" + CStr(oBinItem.m_lSize) + "], " Next If Len(sResult) > 2 Then sResult = Left(sResult, Len(sResult) - 2) GetString = sResult End Function
5.1.8。 CBinItemクラスのソースコード
Binに入れるItemを実装する。
- Itemの名前はm_sName、サイズはm_lSizeで管理します。
- CompareTo関数:現在のItemと比較対象のItemのサイズを比較した結果を返します。
Option Explicit Public m_sName As String Public m_lSize As Long 'BinItem의 size 비교 함수 ' - parameter: 비교대상 BinItem(B) ' - 비교기준: 자기자신 BinItem(A) 'Return 값(Long type) ' 0: 동일함 (A = B) ' 1: 비교대상 BinItem이 더 큼(A < B) ' -1: 자기자신 BinItem이 더 큼(A > B) Public Function CompareTo(oBinItem As CBinItem) As Long Dim i As Long If Me.m_lSize = oBinItem.m_lSize Then i = 0 ElseIf Me.m_lSize < oBinItem.m_lSize Then i = -1 Else i = 1 End If CompareTo = i End Function
5.1.9。 CTimerクラスのソースコード
各アルゴリズムの実行時間を正確に測定するために使用されます。
ソース: https://stackoverflow.com/questions/198409/how-do-you-test-running-time-of-vba-code
Option Explicit Private Type LARGE_INTEGER lowpart As Long highpart As Long End Type Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As LARGE_INTEGER) As Long Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As LARGE_INTEGER) As Long Private m_CounterStart As LARGE_INTEGER Private m_CounterEnd As LARGE_INTEGER Private m_crFrequency As Double Private Const TWO_32 = 4294967296# ' = 256# * 256# * 256# * 256# Private Function LI2Double(LI As LARGE_INTEGER) As Double Dim Low As Double Low = LI.lowpart If Low < 0 Then Low = Low + TWO_32 End If LI2Double = LI.highpart * TWO_32 + Low End Function Private Sub Class_Initialize() Dim PerfFrequency As LARGE_INTEGER QueryPerformanceFrequency PerfFrequency m_crFrequency = LI2Double(PerfFrequency) End Sub Public Sub StartCounter() QueryPerformanceCounter m_CounterStart End Sub Property Get TimeElapsed() As Double Dim crStart As Double Dim crStop As Double QueryPerformanceCounter m_CounterEnd crStart = LI2Double(m_CounterStart) crStop = LI2Double(m_CounterEnd) 'TimeElapsed = 1000# * (crStop - crStart) / m_crFrequency TimeElapsed = Round((crStop - crStart) / m_crFrequency, 4) End Property
<< 関連記事のリスト >>
- 1次元Bin Packingアルゴリズムを活用した作業配分の最適化_1.概要
- 1次元Bin Packingアルゴリズムを活用した作業配分最適化_2.アルゴリズム(1)
- 1次元Bin Packingアルゴリズムを活用した作業配分最適化_2.アルゴリズム(2)
- 1次元Bin Packingアルゴリズムを活用した作業配分最適化_3.実装(1)
- 1次元Bin Packingアルゴリズムを活用した作業配分最適化_3.実装(2)
- 1次元Bin Packingアルゴリズムを活用した作業配分の最適化_4。
- 1次元Bin Packingツール最近の変更(2021-03-21基準)
- 1次元Bin Packingアルゴリズムを活用した作業配分最適化ツール