[trợ giúp] tạo vòng lặp lồng For Next với số vòng lặp phụ thuộc vào người dùng

Liên hệ QC

vanmanhvcu

Thành viên chính thức
Tham gia
27/3/11
Bài viết
85
Được thích
10
Chào tất cả mọi người
tôi có 1 vùng trong bảng Excel như ảnh sau:
1551164152008.png

Range(B3:E10) do người dùng nhấp chuột chọn, số lượng ô trong vùng được chọn hiện tại là 32 ô
và tôi muốn viết code VBA tạo số vòng lặp lồng nhau For Next là số lượng ô trong vùng được chọn là 32 để điền giá trị thay đổi từ 1 đến 3 vào các ô đó
vậy có cách nào tạo vòng lặp lồng mà không phải viết thủ công 32 vòng lặp ra hay không?
nếu có cách nào tốt hơn xin mọi người hãy chỉ dẫn giúp !
PHP:
Sub taoVongLap()
Dim Arr() as integer
Arr()=[B3:E10].value

for Arr(1,1)=1 to 3
    for Arr(1,2)=1 to 3
        for Arr(1,3)=1 to 3
            for Arr(1,4)=1 to 3
                for Arr(2,1)=1 to 3
                    for Arr(2,2)= 1 to 3
                        ..............
                            'tiếp tục đến for Arr(8,4).... thì sẽ rất dài và thủ công
                    next Arr(2,2)
                next Arr(2,1)
            next Arr(1,4)
        next Arr(1,3)
    next Arr(1,2)
next Arr(1,1)

End Sub
 

File đính kèm

  • 1551162367793.png
    1551162367793.png
    7.9 KB · Đọc: 17
Lần chỉnh sửa cuối:
Tôi thấy cứ ngờ ngợ, muốn hỏi chủ topic cái này ứng dụng vào gì? mà sao phải xét nhiều vậy, có thể dùng Solver, hoặc quy hoạch động có thể gần sát với vấn đề này hơn.
Ứng dụng vào hoạt động sản xuất thôi bác @tam888
Tên topic và nơi mà tôi post bài viết là trong chủ đề "Lập trình với Excel" đã nói lên mục đích đó là dùng giải thuật lập trình để tìm đáp án cho bài toán.
Nếu dùng Solver thì chúng ta không thể hiểu được giải thuật của nó là gì
Có thể bác không để ý, trong #13 tôi đã nói là đã thử bằng Solver và tôi thấy rằng Solver có nhược điểm là chỉ tìm ra 1 đáp án duy nhất.
và xin cảm ơn tới @HieuCD @anhtuanle123 @CHAOQUAY đã cho tôi mở mang hơn.
nói thật, tôi vẫn đang phải nghiên cứu để cố gắng hiểu hết dòng code đó với hiểu biết hạn hẹp của mình.
 
Upvote 0
xin cám ơn bác, vậy giúp tôi xử lý bài toán gốc như sau nhé
Bài toán đầy đủ như sau:
View attachment 212992

về đáp án thì có thể có nhiều đáp án đáp ứng yêu cầu
và một trong các đáp án đó là:
View attachment 212993

tôi vẫn chưa xây dựng được hoàn thiện thuật toán tìm kết quả
nếu có thể , xin vui lòng tiếp tục giúp đỡ.
Góp vui, cho bạn thêm code có thể tùy biến khi thêm dòng hoặc cột thay đổi vùng điều kiện là được, code dùng thuật toán so sánh chuỗi 2 điều kiện để loại bỏ nhiều nhất các trường hợp không đúng.
 

File đính kèm

Upvote 0
kiểu dữ liệu giằng co hàng cột kiểu này chắc là tham số cho 1 hàm tính nào đó , như tính mức tối ưu giữa chi phí và lợi nhuận , hoặc trong xây dựng là tính điểm chịu lực tối ưu chẳng hạn , miềng đoán thế ^^!

mình chia sẻ với bác chủ thớt cách mình và 1 số bạn đi theo để giảm thời gian tính toán là thay vì xét cả thảy 28 ô 1 lúc , tức là 28 vòng for , với mỗi vòng 0->3 , tức là 4 giá trị , tương đương 4^28 bước lặp = 72057594037927936 vòng lặp ( con số này chắc phải có 1 siêu máy tính mới tính nổi ) ,
sau khi nghiên cứu công thức của bác , thì thấy rằng thực ra dữ liệu cột này cũng ko liên quan đến cột kia , nên ta đưa về bài toán tính chỉnh hợp trên từng cột 7 ô , tức là 4^7=16384 lần lặp cho 1 cột ,
ta tính 4 cột thì bằng 16384 * 4 = 65536 bước lặp là có thể tìm ra kết quả cho 4 cột !
trong quá trình test thử mình thấy rằng cột có số trường hợp thỏa mãn cho chính cột đó có khoảng 20 trường hợp , cứ cho mỗi cột có 20 là tối đa đi , thì tìm chỉnh hợp theo kết quả cột 20 ^ 4 = 160000 lần lặp nữa là tìm được kết quả cho bảng tính !
nói chung bác cứ tính thử cho 1 cột là sẽ ngộ ra bài toán !
tặng bác cuốn bí kíp để luyện công ^^
book
 
Upvote 0
kiểu dữ liệu giằng co hàng cột kiểu này chắc là tham số cho 1 hàm tính nào đó , như tính mức tối ưu giữa chi phí và lợi nhuận , hoặc trong xây dựng là tính điểm chịu lực tối ưu chẳng hạn , miềng đoán thế ^^!

mình chia sẻ với bác chủ thớt cách mình và 1 số bạn đi theo để giảm thời gian tính toán là thay vì xét cả thảy 28 ô 1 lúc , tức là 28 vòng for , với mỗi vòng 0->3 , tức là 4 giá trị , tương đương 4^28 bước lặp = 72057594037927936 vòng lặp ( con số này chắc phải có 1 siêu máy tính mới tính nổi ) ,
sau khi nghiên cứu công thức của bác , thì thấy rằng thực ra dữ liệu cột này cũng ko liên quan đến cột kia , nên ta đưa về bài toán tính chỉnh hợp trên từng cột 7 ô , tức là 4^7=16384 lần lặp cho 1 cột ,
ta tính 4 cột thì bằng 16384 * 4 = 65536 bước lặp là có thể tìm ra kết quả cho 4 cột !
trong quá trình test thử mình thấy rằng cột có số trường hợp thỏa mãn cho chính cột đó có khoảng 20 trường hợp , cứ cho mỗi cột có 20 là tối đa đi , thì tìm chỉnh hợp theo kết quả cột 20 ^ 4 = 160000 lần lặp nữa là tìm được kết quả cho bảng tính !
nói chung bác cứ tính thử cho 1 cột là sẽ ngộ ra bài toán !
tặng bác cuốn bí kíp để luyện công ^^
book
Nếu làm theo bài này thì đúng là nên chạy theo cột là ngon nhất, vì số thỏa mãn cả 4 cột chỉ có hơn 30.000 trường hợp sau đó xét các trường hợp này trên từng dòng là xong. Nhưng nếu đổi lại độ chênh lệch cao (không phải min=4, max=7) hoặc số dòng cột tăng thêm thì sài cột không chưa chắc đã hợp lý, như trong bài này nếu làm theo dòng thì số trường hợp cần chạy lên tới 2 triệu trường hợp, nói chung nếu chỉ chọn hoặc cột hay dòng thì tổng quát chưa tối ưu lắm, mới đầu tôi cũng tính làm theo cột nhưng thấy không ổn lắm, cuối cùng làm tổng quát là cả cột và dòng luôn nhưng xét riêng từng cái, sau đó dùng chuỗi so sanh cả 2 điều kiện này , nên bài này tôi chạy chỉ có 40 trường hợp , nếu xét đủ điều kiện cột , dòng và giao nhau giữa cột và dòng.
 
Upvote 0
chạy theo cột tuy tưởng là 1 cách giải khác , nhưng thực ra cũng phải chạy qua 28 vòng lặp , bản chất việc chạy 2 bước này là áp dụng nhánh cận lọc ra các trường hợp thỏa theo cột , nhờ đó giảm được việc đi tiếp nếu cột trước chưa thỏa !
thực ra ta vẫn có thể gộp chung vào 1 vòng lặp lớn mà ko cần chia ra 2 bước , nhưng xét điều kiện 7 ô 1 lần , nếu 7 ô trước thỏa thì mới đi tiếp !
 
Upvote 0
chạy theo cột tuy tưởng là 1 cách giải khác , nhưng thực ra cũng phải chạy qua 28 vòng lặp , bản chất việc chạy 2 bước này là áp dụng nhánh cận lọc ra các trường hợp thỏa theo cột , nhờ đó giảm được việc đi tiếp nếu cột trước chưa thỏa !
thực ra ta vẫn có thể gộp chung vào 1 vòng lặp lớn mà ko cần chia ra 2 bước , nhưng xét điều kiện 7 ô 1 lần , nếu 7 ô trước thỏa thì mới đi tiếp !
Thực chất các code trên đều tính theo 2 bước, Cột _ Dòng hoặc Dòng _ Cột. Chỉ khác nhau là cách loại trừ, dẫn đến khối lượng tính thay đổi nên code nhanh hoặc chậm hơn.
Nếu tính trực tiếp trên mảng 4*7 chắc có lẽ phải dùng thuật toán khác
 
Upvote 0
Nếu làm theo bài này thì đúng là nên chạy theo cột là ngon nhất, vì số thỏa mãn cả 4 cột chỉ có hơn 30.000 trường hợp sau đó xét các trường hợp này trên từng dòng là xong. Nhưng nếu đổi lại độ chênh lệch cao (không phải min=4, max=7) hoặc số dòng cột tăng thêm thì sài cột không chưa chắc đã hợp lý, như trong bài này nếu làm theo dòng thì số trường hợp cần chạy lên tới 2 triệu trường hợp, nói chung nếu chỉ chọn hoặc cột hay dòng thì tổng quát chưa tối ưu lắm, mới đầu tôi cũng tính làm theo cột nhưng thấy không ổn lắm, cuối cùng làm tổng quát là cả cột và dòng luôn nhưng xét riêng từng cái, sau đó dùng chuỗi so sanh cả 2 điều kiện này , nên bài này tôi chạy chỉ có 40 trường hợp , nếu xét đủ điều kiện cột , dòng và giao nhau giữa cột và dòng.
Nếu nói về bài toán tổng quát tôi xin chia sẻ thực tế như sau
1. Độ chênh lệch của tôi luôn luôn fixed trong khoảng (4-7)
2. Số lượng cột luôn luôn < số lượng hàng
3. Số lượng hàng Max là 24 ( rất ít khi có)
4. Giá trị trong vùng tìm kiếm luôn luôn từ 0 đến 4 ( bài toán này chỉ là đến 3)
 
Upvote 0
@vanmanhvcu
Giả sử với file tổng quát thì bạn có thể áng chừng khoảng bao nhiêu nghiệm?
 
Upvote 0
coi bài thớt này thấy mấy bạn dùng từ: thuật toán vét cạn + chỉnh hợp ...
thấy ít người xài quá ... coi tới lui mà ko hiểu cơ bản nó như thế nào là thuật toán vét cạn ??? tại vì có nghe bên ngoài có người nói tới thuật toán vét cạn .... nên cũng đang tò mò chút ???
Tiện đây bạn nào cho 1 VD rất cơ bản + code cơ bản làm sao để người đọc hiểu được đó là thuật toán vét cạn cho Mạnh học với 1 chút
Xin cảm ơn
 
Upvote 0
hi bác Mạnh , thực ra thì từ vét cạn ko biết nó có từ bao giờ , chỉ biết trong các tài liệu chính quy thì nó là từ chuẩn được dùng ,
vét : là vơ vét
cạn : là cạn kiệt
chắc ý là vét sạch sành sanh ấy ^^
về ví dụ thì mình xin mạn phép chia sẻ như sau :
ví dụ ta có 1 bài toán như sau , liệt kê các số với 3 chữ số abc , kèm điều kiện là các chữ số trong chuỗi ràng buộc như sau , chữ số 1 là chẵn , số 2 =5 hoặc 7 , số 3 là số lẻ -> vd : 253 , 471
ta có code macro sau !

Mã:
Sub ex()
  
    Dim i, j, k As Integer
    Dim v As String
    Dim m As Integer
    m = 1
  
    Dim count As Integer '-----dem so buoc lap
    count = 0
  
    For i = 0 To 9
        For j = 0 To 9
            For k = 0 To 9
              
                If i Mod 2 = 0 And (j = 5 Or j = 7) And k Mod 2 = 1 Then
              
                    v = "_" & i & j & k 'tinh toan
                    Range("A" & m) = v  '
                    m = m + 1           '
                  
                End If
              
                count = count + 1
              
            Next k
        Next j
    Next i
          
    MsgBox count '-----so buoc xu ly
          
End Sub

ta thấy chạy xong thì chương trình chạy đủ 10^3=10*10*10=1000 vòng lặp

nhưng nếu chặn bên ngoài
Mã:
Sub ex()
   
    Dim i, j, k As Integer
    Dim v As String
    Dim m As Integer
    m = 1
   
    Dim count As Integer '-----dem so buoc lap
    count = 0
   
    For i = 0 To 9
      If i Mod 2 = 0 Then '---1
        For j = 0 To 9
          If j = 5 Or j = 7 Then '----2
            For k = 0 To 9
                If k Mod 2 = 1 Then '----3
               
                    v = "_" & i & j & k 'tinh toan
                    Range("A" & m) = v  '
                    m = m + 1           '
                   
                End If '----3
                count = count + 1
            Next k
          End If '----2
        Next j
      End If  '----1
    Next i
           
    MsgBox count '-----so buoc xu ly
           
End Sub

thì chỉ chạy 100 bước là ra kết quả rùi , tức là vét có chọn lọc ^^!
 
Lần chỉnh sửa cuối:
Upvote 0
kiểu dữ liệu giằng co hàng cột kiểu này chắc là tham số cho 1 hàm tính nào đó , như tính mức tối ưu giữa chi phí và lợi nhuận , hoặc trong xây dựng là tính điểm chịu lực tối ưu chẳng hạn , miềng đoán thế ^^!

mình chia sẻ với bác chủ thớt cách mình và 1 số bạn đi theo để giảm thời gian tính toán là thay vì xét cả thảy 28 ô 1 lúc , tức là 28 vòng for , với mỗi vòng 0->3 , tức là 4 giá trị , tương đương 4^28 bước lặp = 72057594037927936 vòng lặp ( con số này chắc phải có 1 siêu máy tính mới tính nổi ) ,
sau khi nghiên cứu công thức của bác , thì thấy rằng thực ra dữ liệu cột này cũng ko liên quan đến cột kia , nên ta đưa về bài toán tính chỉnh hợp trên từng cột 7 ô , tức là 4^7=16384 lần lặp cho 1 cột ,
ta tính 4 cột thì bằng 16384 * 4 = 65536 bước lặp là có thể tìm ra kết quả cho 4 cột !
trong quá trình test thử mình thấy rằng cột có số trường hợp thỏa mãn cho chính cột đó có khoảng 20 trường hợp , cứ cho mỗi cột có 20 là tối đa đi , thì tìm chỉnh hợp theo kết quả cột 20 ^ 4 = 160000 lần lặp nữa là tìm được kết quả cho bảng tính !
nói chung bác cứ tính thử cho 1 cột là sẽ ngộ ra bài toán !
tặng bác cuốn bí kíp để luyện công ^^
book
Nhìn mục lục rất mê, tiếc rằng không đủ sức tiêu hóa nội dung
Nếu nói về bài toán tổng quát tôi xin chia sẻ thực tế như sau
1. Độ chênh lệch của tôi luôn luôn fixed trong khoảng (4-7)
2. Số lượng cột luôn luôn < số lượng hàng
3. Số lượng hàng Max là 24 ( rất ít khi có)
4. Giá trị trong vùng tìm kiếm luôn luôn từ 0 đến 4 ( bài toán này chỉ là đến 3)
Thay sub KetQua bằng sub TestRow_Ketqua để chạy số dòng số cột thay đổi, chỉ nhập lại địa chỉ dữ liệu chuẩn
Số dòng tăng sẽ làm code chậm rất nhiều, có thể thiếu bộ nhớ
Mã:
  Dim Arr() As Long, jArr(), colArr(), cArr() As Long
  Dim tRow(), tCol(), dkR1(), dkR2(), dkC1, dkC2
  Dim M As Long, N As Long, Tong, tmp
  Dim i As Long, j As Long, c As Long, k As Long
  Dim sRow As Long, sCol As Long

Sub GPE2()
  Tg = Timer
  dkR1 = Range("F5:F11").Value:  dkR2 = Range("J5:J11").Value 'Dieu kien Dong
  tRow = Range("B2:E4").Value 'Tham so dong
  sRow = UBound(dkR1, 1):  sCol = UBound(tRow, 2)
  For j = 1 To sCol
    tRow(1, j) = tRow(1, j) * tRow(3, j) / tRow(2, j)
  Next j
  tCol = Range("A5:A11").Value 'Tham so cot
  dkC1 = 4:  dkC2 = 7 ' Dieu kien Cot
  N = 4 'So gia tri lua chon
  Call ChinhHop
  Call AddCol
  Range("M5", Range("P1000000").End(xlUp)).ClearContents
  Call TestRow_KetQua
  [l2] = Timer - Tg
End Sub

Private Sub ChinhHop()
  M = N ^ sRow
  ReDim cArr(1 To sRow, 1 To M)
  For j = 2 To M
    For i = sRow To 1 Step -1
      If cArr(i, j - 1) < 3 Then
        cArr(i, j) = cArr(i, j - 1) + 1
        For k = i + 1 To sRow
          cArr(k, j) = 0
        Next k
        For k = 1 To i - 1
          cArr(k, j) = cArr(k, j - 1)
        Next k
        Exit For
      End If
    Next i
  Next j
End Sub

Private Sub AddCol()
  ReDim colArr(1 To sCol)
  For j = 1 To sCol
    k = 0
    ReDim jArr(1 To 1)
    For c = 1 To M
      Tong = tRow(2, j)
      ReDim Arr(1 To sRow)
      For i = 1 To sRow
        tmp = cArr(i, c)
        If tmp > 0 Then
          If tRow(1, j) * tCol(i, 1) * tmp > dkR2(i, 1) Then GoTo Thoat
          Tong = Tong - tCol(i, 1) * tmp
          If Tong < dkC1 Then GoTo Thoat
        End If
      Next i
      If Tong <= dkC2 Then
        For i = 1 To sRow
          Arr(i) = cArr(i, c)
        Next i
        k = k + 1
        ReDim Preserve jArr(1 To k)
        jArr(k) = Arr
      End If
Thoat:
    Next c
    colArr(j) = jArr
  Next j
  Erase cArr
End Sub

Private Sub TestRow_KetQua()
  Dim tArr() As Long, ChayNhanhLen As String
  ReDim Arr(1 To sRow, 1 To sCol)
  ReDim tArr(1 To 2, 1 To sCol)
  For j = 1 To sCol
    tArr(1, j) = 1: tArr(2, j) = UBound(colArr(j))
  Next j
  k = 0
  Do While ChayNhanhLen = Empty
    For i = 1 To sRow
      Tong = 0
      For j = 1 To sCol
        Tong = Tong + tRow(1, j) * colArr(j)(tArr(1, j))(i)
      Next j
      Tong = Tong * tCol(i, 1)
      If Tong < dkR1(i, 1) Or Tong > dkR2(i, 1) Then GoTo Thoat
    Next i
    For i = 1 To sRow
      For j = 1 To sCol
        Arr(i, j) = colArr(j)(tArr(1, j))(i)
      Next j
    Next i
    k = k + 1
    Range("M" & (sRow + 1) * (k - 1) + 5).Resize(sRow, sCol) = Arr
Thoat:
    For j = sCol To 1 Step -1
      If tArr(1, j) < tArr(2, j) Then
        tArr(1, j) = tArr(1, j) + 1
        For i = j + 1 To sCol
          tArr(1, i) = 1
        Next i
        Exit For
      Else
        If j = 1 Then Exit Sub
      End If
    Next j
  Loop
End Sub
 
Upvote 0
hi bác Mạnh , thực ra thì từ vét cạn ko biết nó có từ bao giờ , chỉ biết trong các tài liệu chính quy thì nó là từ chuẩn được dùng ,
vét : là vơ vét
cạn : là cạn kiệt
chắc ý là vét sạch sành sanh ấy ^^
về ví dụ thì mình xin mạn phép chia sẻ như sau :
ví dụ ta có 1 bài toán như sau , liệt kê các số với 3 chữ số abc , kèm điều kiện là các chữ số trong chuỗi ràng buộc như sau , chữ số 1 là chẵn , số 2 =5 hoặc 7 , số 3 là số lẻ -> vd : 253 , 471
ta có code macro sau !

Mã:
Sub ex()
 
    Dim i, j, k As Integer
    Dim v As String
    Dim m As Integer
    m = 1
 
    Dim count As Integer '-----dem so buoc lap
    count = 0
 
    For i = 0 To 9
        For j = 0 To 9
            For k = 0 To 9
             
                If i Mod 2 = 0 And (j = 5 Or j = 7) And k Mod 2 = 1 Then
             
                    v = "_" & i & j & k 'tinh toan
                    Range("A" & m) = v  '
                    m = m + 1           '
                 
                End If
             
                count = count + 1
             
            Next k
        Next j
    Next i
         
    MsgBox count '-----so buoc xu ly
         
End Sub

ta thấy chạy xong thì chương trình chạy đủ 10^3=10*10*10=1000 vòng lặp

nhưng nếu chặn bên ngoài
Mã:
Sub ex()
  
    Dim i, j, k As Integer
    Dim v As String
    Dim m As Integer
    m = 1
  
    Dim count As Integer '-----dem so buoc lap
    count = 0
  
    For i = 0 To 9
      If i Mod 2 = 0 Then '---1
        For j = 0 To 9
          If j = 5 Or j = 7 Then '----2
            For k = 0 To 9
                If k Mod 2 = 1 Then '----3
              
                    v = "_" & i & j & k 'tinh toan
                    Range("A" & m) = v  '
                    m = m + 1           '
                  
                End If '----3
                count = count + 1
            Next k
          End If '----2
        Next j
      End If  '----1
    Next i
          
    MsgBox count '-----so buoc xu ly
          
End Sub

thì chỉ chạy 100 bước là ra kết quả rùi , tức là vét có chọn lọc ^^!
Mình nghĩ "vét có chọn lọc" thì chay 50 bước thôi chứ nhỉ. Híc
Thân
 
Upvote 0
Chắc Anh cò lại có cách Vét xúc tích, ngắn gọn hơn hỷ ??!! :p
Có gì mà "súc" với "tích" chú Mạnh ơi
Số đầu tiên là số chẵn thì chạy từ 0 đến 8 step 2 (5 em)
Số thứ hai la 5 hoặc 7 thì chạy từ 5 đến 7 step 2 (2 em)
Số cuối là số lẻ thì chạy từ 1 đến 9 step 2 (5 em)
5 em, 2 em rồi lại 5 em thì ....50 chục bước thôi. Híc
Thân
 
Upvote 0
hùi trước mình cũng nhìn nhận vấn đề như bác đó !
nhưng bác thử hình dung thế này , 50 đó chỉ là kết quả của thôi , còn 100 là số bước đi để tìm ra kết quả đó (100 này cũng là đại khái ) , cũng giống như 1 cái cây ,
có thân cây , cành , lá và quả !
giờ muốn tìm số quả trên cây , giả xử cái cây rất to , cách làm chắc ăn nhất là mình phải tìm từng cành 1 , 1 số cành sẽ không có quả , nhưng giả xử có tín hiệu nào đó để biết được cành muốn kiểm tra không có quả để khỏi tìm tốn công , thì ta giảm được thời gian kiểm tra và tìm kiếm !

như trong bài thì bước 1 , ta phải chạy 10 bước , có 5 bước thỏa để đi tiếp và 5 bước không thỏa !
5 bước không thỏa này thì cũng phải tính toán thì nó mới biết là không thỏa chứ nhỉ nên coi như là thêm 5 bước !

5 bước thỏa sẽ đi đến cấp sâu hơn , gồm 10 bước , có 2 bước thỏa để đi tiếp và 8 bước không thỏa !

2 bước thỏa sẽ đi đến cấp sâu hơn , gồm 10 bước (chắc chắn 1 rùi ) , vì trong cấp thứ 3 này làm gì kệ nó , miễn chạy đủ 10 bước là được !

vậy nếu tính các con đường đi đến cấp cuối cùng thì có 5 * 2 * 10 = 100 bước !
5 bước không thỏa đầu tiên !
5 bước thỏa đầu tiên * 8 bước đi mà không đến đích mức thứ 2 = 40 bước không thỏa thứ 2 !

tổng cộng có 100 + 5 + 40 =145 bước phải đi !
là bước phải đi , ko phải là bước đến đích !
 
Upvote 0
Cuộn trải ra thì thành tấm, nếu không cần chia chiều rộng mà chỉ chia chiều dài thì coi như thanh.
GPE có bài toán tối ưu hóa cắt tấm, cắt thanh tám mười đời rồi.
 
Upvote 0
Cuộn trải ra thì thành tấm, nếu không cần chia chiều rộng mà chỉ chia chiều dài thì coi như thanh.
GPE có bài toán tối ưu hóa cắt tấm, cắt thanh tám mười đời rồi.
Sorry bác, bài này chỉ chia chiều rộng thôi !
Bài đã được tự động gộp:

Nhìn mục lục rất mê, tiếc rằng không đủ sức tiêu hóa nội dung

Thay sub KetQua bằng sub TestRow_Ketqua để chạy số dòng số cột thay đổi, chỉ nhập lại địa chỉ dữ liệu chuẩn
Số dòng tăng sẽ làm code chậm rất nhiều, có thể thiếu bộ nhớ
Mã:
  Dim Arr() As Long, jArr(), colArr(), cArr() As Long
  Dim tRow(), tCol(), dkR1(), dkR2(), dkC1, dkC2
  Dim M As Long, N As Long, Tong, tmp
  Dim i As Long, j As Long, c As Long, k As Long
  Dim sRow As Long, sCol As Long

Sub GPE2()
  Tg = Timer
  dkR1 = Range("F5:F11").Value:  dkR2 = Range("J5:J11").Value 'Dieu kien Dong
  tRow = Range("B2:E4").Value 'Tham so dong
  sRow = UBound(dkR1, 1):  sCol = UBound(tRow, 2)
  For j = 1 To sCol
    tRow(1, j) = tRow(1, j) * tRow(3, j) / tRow(2, j)
  Next j
  tCol = Range("A5:A11").Value 'Tham so cot
  dkC1 = 4:  dkC2 = 7 ' Dieu kien Cot
  N = 4 'So gia tri lua chon
  Call ChinhHop
  Call AddCol
  Range("M5", Range("P1000000").End(xlUp)).ClearContents
  Call TestRow_KetQua
  [l2] = Timer - Tg
End Sub

Private Sub ChinhHop()
  M = N ^ sRow
  ReDim cArr(1 To sRow, 1 To M)
  For j = 2 To M
    For i = sRow To 1 Step -1
      If cArr(i, j - 1) < 3 Then
        cArr(i, j) = cArr(i, j - 1) + 1
        For k = i + 1 To sRow
          cArr(k, j) = 0
        Next k
        For k = 1 To i - 1
          cArr(k, j) = cArr(k, j - 1)
        Next k
        Exit For
      End If
    Next i
  Next j
End Sub

Private Sub AddCol()
  ReDim colArr(1 To sCol)
  For j = 1 To sCol
    k = 0
    ReDim jArr(1 To 1)
    For c = 1 To M
      Tong = tRow(2, j)
      ReDim Arr(1 To sRow)
      For i = 1 To sRow
        tmp = cArr(i, c)
        If tmp > 0 Then
          If tRow(1, j) * tCol(i, 1) * tmp > dkR2(i, 1) Then GoTo Thoat
          Tong = Tong - tCol(i, 1) * tmp
          If Tong < dkC1 Then GoTo Thoat
        End If
      Next i
      If Tong <= dkC2 Then
        For i = 1 To sRow
          Arr(i) = cArr(i, c)
        Next i
        k = k + 1
        ReDim Preserve jArr(1 To k)
        jArr(k) = Arr
      End If
Thoat:
    Next c
    colArr(j) = jArr
  Next j
  Erase cArr
End Sub

Private Sub TestRow_KetQua()
  Dim tArr() As Long, ChayNhanhLen As String
  ReDim Arr(1 To sRow, 1 To sCol)
  ReDim tArr(1 To 2, 1 To sCol)
  For j = 1 To sCol
    tArr(1, j) = 1: tArr(2, j) = UBound(colArr(j))
  Next j
  k = 0
  Do While ChayNhanhLen = Empty
    For i = 1 To sRow
      Tong = 0
      For j = 1 To sCol
        Tong = Tong + tRow(1, j) * colArr(j)(tArr(1, j))(i)
      Next j
      Tong = Tong * tCol(i, 1)
      If Tong < dkR1(i, 1) Or Tong > dkR2(i, 1) Then GoTo Thoat
    Next i
    For i = 1 To sRow
      For j = 1 To sCol
        Arr(i, j) = colArr(j)(tArr(1, j))(i)
      Next j
    Next i
    k = k + 1
    Range("M" & (sRow + 1) * (k - 1) + 5).Resize(sRow, sCol) = Arr
Thoat:
    For j = sCol To 1 Step -1
      If tArr(1, j) < tArr(2, j) Then
        tArr(1, j) = tArr(1, j) + 1
        For i = j + 1 To sCol
          tArr(1, i) = 1
        Next i
        Exit For
      Else
        If j = 1 Then Exit Sub
      End If
    Next j
  Loop
End Sub
các bác @HieuCD @anhtuanle123 @CHAOQUAY có thể giải thích cụ thể từng bước giải thuật để cho mọi người cùng hiểu được không?
tôi và có thể có cả người khác cũng đang chập chững VBA, xem code các bác thì tiêu hóa chưa được tốt lắm, mong thông cảm.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom