Option Explicit
'v2
Private Const N_BOX = 3
Private Const N_PREDMET = 74
Private Const K_BOX = 50 '1000
Sub test()
CloseEmptyWb
FindBestСombination nBox:=N_BOX, rSource:=Лист1.Range("B2").Resize(K_BOX, N_PREDMET)
End Sub
Private Sub FindBestСombination(nBox As Long, rSource As Range)
Dim aSour As Variant
aSour = rSource.Value
Dim aIndx As Variant, flagExit As Boolean
ReDim aIndx(1 To nBox)
Init_aIndx aIndx
Dim aComb As Variant, combItem As Variant
ReDim aComb(1 To UBound(aSour, 2))
Dim dt As Date
Dim curUniqCount As Long
Do
'Debug.Print Join(aIndx, " ")
If Not HasDupies(aIndx) Then
If IsIncreasing(aIndx) Then
curUniqCount = CountUniq(aIndx, aSour)
If IsEmpty(aComb(curUniqCount)) Then
ReDim combItem(1 To 1)
Else
combItem = aComb(curUniqCount)
ReDim Preserve combItem(1 To UBound(combItem) + 1)
End If
combItem(UBound(combItem)) = aIndx
aComb(curUniqCount) = combItem
End If
End If
If dt < Now - TimeSerial(0, 0, 5) Then
dt = Now
Application.StatusBar = Left("Перебираю " & Join(aIndx, " "), 125)
End If
PlusOne aIndx, 1, flagExit, UBound(aSour, 1)
If flagExit Then Exit Do
DoEvents
Loop
PrintResult aComb, rSource
Application.StatusBar = False
End Sub
Private Sub PrintResult(aComb, rSource As Range)
Dim rTarget As Range
Set rTarget = Workbooks.Add(1).Sheets(1).Cells(1, 1)
rTarget.Cells(1, 1).Resize(1, 3).Value = Array("Уникальных", "Коробки", Empty)
Set rTarget = rTarget.Cells(2, 1)
Dim aSource As Variant
aSource = rSource.Columns(0).Value
Dim yc As Long, yb As Long, arr As Variant, hrr As Variant, brr As Variant
For yc = UBound(aComb) To LBound(aComb) Step -1
If Not IsEmpty(aComb(yc)) Then
Application.StatusBar = "Вывожу " & yc
arr = aComb(yc)
ReDim brr(1 To UBound(arr), 1 To 3)
If rTarget.Row + UBound(brr, 1) > rTarget.Parent.Rows.Count Then Exit For
For yb = LBound(arr) To UBound(arr)
hrr = GetHeader(arr(yb), aSource)
brr(yb, 1) = yc
brr(yb, 2) = Join(arr(yb), ", ")
brr(yb, 3) = Join(hrr, ", ")
Next
Set rTarget = rTarget.Cells(1, 1).Resize(UBound(brr, 1), UBound(brr, 2))
rTarget.Value = brr
Application.Goto rTarget
Set rTarget = rTarget.Cells(rTarget.Rows.Count + 1, 1)
End If
Next
Application.Goto Cells(1, 1)
rTarget.Parent.Parent.Saved = True
End Sub
Private Function GetHeader(arr As Variant, aSource As Variant) As Variant
Dim hrr As Variant, yh As Long
ReDim hrr(LBound(arr) To UBound(arr))
yh = LBound(hrr) - 1
Dim ya As Variant
For Each ya In arr
yh = yh + 1
hrr(yh) = aSource(ya, 1)
Next
GetHeader = hrr
End Function
Private Function IsIncreasing(aIndx As Variant) As Boolean
Dim xi As Long, hi As Long
For xi = LBound(aIndx) To UBound(aIndx) - 1
For hi = xi + 1 To UBound(aIndx)
If aIndx(xi) >= aIndx(hi) Then
IsIncreasing = False
Exit Function
End If
Next
Next
IsIncreasing = True
End Function
Private Function HasDupies(aIndx As Variant) As Boolean
Dim xi As Long, hi As Long
For xi = LBound(aIndx) To UBound(aIndx) - 1
For hi = xi + 1 To UBound(aIndx)
If aIndx(xi) = aIndx(hi) Then
HasDupies = True
Exit Function
End If
Next
Next
End Function
Private Sub PlusOne(aIndx As Variant, level As Long, flagExit As Boolean, maxIndex As Long)
If flagExit Then Exit Sub
If aIndx(level) < maxIndex Then
aIndx(level) = aIndx(level) + 1
' ShiftRight aIndx, level, flagExit, maxIndex, False
Else
If level < UBound(aIndx) Then
Dim xi As Long
For xi = LBound(aIndx) To level
aIndx(xi) = 1 'xi
Next
' Dim flagPlus As Boolean
' ShiftRight aIndx, level, flagExit, maxIndex, flagPlus
'
' If flagPlus Or True Then
PlusOne aIndx, level + 1, flagExit, maxIndex
' End If
Else
flagExit = True
End If
End If
End Sub
'Private Sub ShiftRight(aIndx As Variant, level As Long, flagExit As Boolean, maxIndex As Long, flagPlus As Boolean)
' Exit Sub
' Dim xi As Long
' For xi = level + 1 To UBound(aIndx)
' If aIndx(xi) <= aIndx(xi - 1) Then
' If aIndx(xi) < maxIndex Then
' aIndx(xi) = aIndx(xi - 1) + 1
' If xi = level + 1 Then
' flagPlus = True
' End If
' Else
' flagExit = True
' Exit Sub
' End If
' End If
' Next
'
'End Sub
Private Function CountUniq(aIndx As Variant, aSour As Variant) As Long
Dim iInd As Long, iCount As Long, xs As Long, ys As Long
Dim aDone As Variant
ReDim aDone(1 To UBound(aSour, 2)) As Boolean
For iInd = LBound(aIndx) To UBound(aIndx)
ys = aIndx(iInd)
For xs = 1 To UBound(aSour, 2)
If aSour(ys, xs) = 1 Then
If Not aDone(xs) Then
aDone(xs) = True
iCount = iCount + 1
End If
End If
Next
Next
CountUniq = iCount
End Function
Private Sub Init_aIndx(aIndx As Variant)
Dim iInd As Long
For iInd = LBound(aIndx) To UBound(aIndx)
aIndx(iInd) = 1 'iInd
Next
End Sub
Private Sub CloseEmptyWb()
Dim wb As Workbook
For Each wb In Application.Workbooks
If wb.Path = "" Then wb.Close False
Next
End Sub
|