Tìm các giá trị cộng lại thỏa giá trị cho trước

Liên hệ QC

thao nguyen01

Thành viên thường trực
Tham gia
8/12/19
Bài viết
241
Được thích
30
Kính gửi anh/chị trên diễn đàn,

Em đang bị vướng vấn đề sau ạ: Em có một dãy các số liệu từ A4:A386, em có ô mục tiêu là ô D2. Em muốn tìm các giá trị trong cột A cộng lại bằng 213962,43 ạ. Em đã thử với solver nhưng do cột A có nhiều biến nên khi em chạy solver báo lỗi "Too many Variable Cells". Nên em nghĩ bài này không thể dùng solver được ạ. Anh/chị xem giúp em ạ. Em cảm ơn nhiều ạ.
 

File đính kèm

  • BOOK1.xls
    45 KB · Đọc: 32
Không biết là bạn hỏi hay đố vì dữ liệu giống hệt bài ở đây, trong đó có cả code luôn (mình không liên quan đến tác giả nhé).
Đây là bài toán ba lô (knapsack) tra tineegs Việt hay tiếng Anh đều có.
Cái link bạn đưa ra, tôi chưa xem nhưng cũng bái phục tác giả. Code Python mà dịch ra được VBA

Tôi không nói là không thể dịch. Bởi vì nếu không thẻ thì tôi đã nói là "dóc". Nhưng Python dùng đủ loại thư viện, hầu hết viết bằng C, hoặc refactored thành C. Dịch mấy cái code cần trong các thư viện mới tá hoả.
 
Upvote 0
Đây là code đơn thuần tính toán thôi chứ không phải thư viện đâu bác. Dữ liệu trong file của họ giống hệt file này.
Mã:
Option Explicit

Sub test()

Dim dGoal As Double: dGoal = 213962.43
Dim a() As Variant: a = Range("A4:A386").Value
Dim uvA As Integer: uvA = UBound(a)
Dim vS(1 To 383) As Variant
Dim i, fi, j, k As Integer
Dim mintnow, mint As Double
Dim now As Double
Dim chosen As Integer
Dim luui, luuj, luuk, c As Integer

For i = 1 To uvA
    vS(i) = False
Next

For fi = 1 To uvA
    now = a(fi, 1)
    vS(fi) = True
    mintnow = 1000000000000#
    Do While True
        mint = mintnow
        chosen = 0
        luui = -1
        luuj = -1
        luuk = -1
        
        For i = 1 To (uvA - 2)
            If Not vS(i) Then
                For j = (i + 1) To (uvA - 1)
                    If Not vS(j) Then
                        For k = (j + 1) To uvA
                            If Not vS(k) Then
                                If Abs(now + a(i, 1) + a(j, 1) + a(k, 1) - dGoal) < mint Then
                                    mint = Abs(now + a(i, 1) + a(j, 1) + a(k, 1) - dGoal)
                                    luui = i
                                    luuj = j
                                    luuk = k
                                    chosen = 3
                                End If
                            End If
                        Next
                    End If
                Next
            End If
        Next
        
        For i = 1 To uvA
            If Not vS(i) Then
                If Abs(now + a(i, 1) - dGoal) < mint Then
                    mint = Abs(now + a(i, 1) - dGoal)
                    luui = i
                    chosen = 1
                End If
            End If
        Next
        
        For i = 1 To (uvA - 1)
            If Not vS(i) Then
                For j = (i + 1) To uvA
                    If Not vS(j) Then
                        If Abs(now + a(i, 1) + a(j, 1) - dGoal) < mint Then
                            mint = Abs(now + a(i, 1) + a(j, 1) - dGoal)
                            luui = i
                            luuj = j
                            chosen = 1
                        End If
                        
                    End If
                Next
            End If
        Next
        
        If chosen = 1 Then
            now = now + a(luui, 1)
            vS(luui) = True
        End If
        
        If chosen = 2 Then
            now = now + a(luui, 1) + a(luuj, 1)
            vS(luui) = True
            vS(luuj) = True
        End If
        
        If chosen = 3 Then
            now = now + a(luui, 1) + a(luuj, 1) + a(luuk, 1)
            vS(luui) = True
            vS(luuj) = True
            vS(luuk) = True
        End If
        
        If Abs(now - dGoal) < mintnow Then
            mintnow = Abs(now - dGoal)
            If mintnow < 0.001 Then
                Do While True
                    Debug.Print "--------------------------------"
                    Debug.Print "Chosen list:"
                    c = 0
                    For i = 1 To uvA
                        If vS(i) Then
                            Debug.Print a(i, 1)
                            c = c + 1
                        End If
                    Next
                    Debug.Print "Total numbers: " & c
                    Debug.Print "Opt sum: " & now
                    Debug.Print "Epsilon: " & mintnow
                    Exit Do
                Loop
            End If
        Else
            Exit Do
        End If
    Loop
Next
End Sub
 
Upvote 0
Không biết là bạn hỏi hay đố vì dữ liệu giống hệt bài ở đây, trong đó có cả code luôn (mình không liên quan đến tác giả nhé).

Dạ, em hỏi thật ạ. Vì em đang vướng vấn đề đó và em đã dùng solver không ra, nên em đã lên mạng tìm nhưng em không tìm ra cách giải. Bài anh gửi link em có xem trước đó, nhưng khi bấm chạy code thì không thấy ra kết quả anh. Vì dùng cả solver và cách theo link đó không được nên em đăng bài trên diễn đàn mong anh/chị giúp ạ. Em chạy code quay vòng vòng, sau đó em không thấy kết quả hiện ra ở cột nào ạ. Vì em không muốn dùng dữ liệu của mình nên dùng ví dụ mô phỏng theo link ạ.
 
Lần chỉnh sửa cuối:
Upvote 0
Đây là code đơn thuần tính toán thôi chứ không phải thư viện đâu bác. Dữ liệu trong file của họ giống hệt file này.
Mã:
Option Explicit

Sub test()

Dim dGoal As Double: dGoal = 213962.43
Dim a() As Variant: a = Range("A4:A386").Value
Dim uvA As Integer: uvA = UBound(a)
Dim vS(1 To 383) As Variant
Dim i, fi, j, k As Integer
Dim mintnow, mint As Double
Dim now As Double
Dim chosen As Integer
Dim luui, luuj, luuk, c As Integer

For i = 1 To uvA
    vS(i) = False
Next

For fi = 1 To uvA
    now = a(fi, 1)
    vS(fi) = True
    mintnow = 1000000000000#
    Do While True
        mint = mintnow
        chosen = 0
        luui = -1
        luuj = -1
        luuk = -1
       
        For i = 1 To (uvA - 2)
            If Not vS(i) Then
                For j = (i + 1) To (uvA - 1)
                    If Not vS(j) Then
                        For k = (j + 1) To uvA
                            If Not vS(k) Then
                                If Abs(now + a(i, 1) + a(j, 1) + a(k, 1) - dGoal) < mint Then
                                    mint = Abs(now + a(i, 1) + a(j, 1) + a(k, 1) - dGoal)
                                    luui = i
                                    luuj = j
                                    luuk = k
                                    chosen = 3
                                End If
                            End If
                        Next
                    End If
                Next
            End If
        Next
       
        For i = 1 To uvA
            If Not vS(i) Then
                If Abs(now + a(i, 1) - dGoal) < mint Then
                    mint = Abs(now + a(i, 1) - dGoal)
                    luui = i
                    chosen = 1
                End If
            End If
        Next
       
        For i = 1 To (uvA - 1)
            If Not vS(i) Then
                For j = (i + 1) To uvA
                    If Not vS(j) Then
                        If Abs(now + a(i, 1) + a(j, 1) - dGoal) < mint Then
                            mint = Abs(now + a(i, 1) + a(j, 1) - dGoal)
                            luui = i
                            luuj = j
                            chosen = 1
                        End If
                       
                    End If
                Next
            End If
        Next
       
        If chosen = 1 Then
            now = now + a(luui, 1)
            vS(luui) = True
        End If
       
        If chosen = 2 Then
            now = now + a(luui, 1) + a(luuj, 1)
            vS(luui) = True
            vS(luuj) = True
        End If
       
        If chosen = 3 Then
            now = now + a(luui, 1) + a(luuj, 1) + a(luuk, 1)
            vS(luui) = True
            vS(luuj) = True
            vS(luuk) = True
        End If
       
        If Abs(now - dGoal) < mintnow Then
            mintnow = Abs(now - dGoal)
            If mintnow < 0.001 Then
                Do While True
                    Debug.Print "--------------------------------"
                    Debug.Print "Chosen list:"
                    c = 0
                    For i = 1 To uvA
                        If vS(i) Then
                            Debug.Print a(i, 1)
                            c = c + 1
                        End If
                    Next
                    Debug.Print "Total numbers: " & c
                    Debug.Print "Opt sum: " & now
                    Debug.Print "Epsilon: " & mintnow
                    Exit Do
                Loop
            End If
        Else
            Exit Do
        End If
    Loop
Next
End Sub

Dạ, anh chạy code trên có ra kết quả không ạ. Em chạy không ra ạ
 
Upvote 0
Kết quả hiện ra ở cửa sổ Immediate window trong VBE mà bạn.

Dạ, em cảm ơn anh ạ. Vì trước giờ em xem kết quả ngoài bảng tính excel nên em không biết là kết quả này hiện ở Immediate window ạ.
Nhưng khi em vô trong Immediate window xem kết quả thì mới thấy với code trên thì kết quả sai ạ. Kết quả do code chạy ra là 13847347,88 không phải là 213962,43 ạ.
Em cảm ơn anh đã xem và hướng dẫn em ở bài trên ạ. Em chúc anh cuối tuần vui vẻ.
 
Lần chỉnh sửa cuối:
Upvote 0
Mình đã xem lại thì thấy kết quả ra sai, có khi tác giả cố tình cho sai để mọi người hỏi cũng nên, bạn vào đó hỏi thử xem đỡ mất công tìm kiếm.
 
Upvote 0
Bạn đã có kết quả chưa bạn, mình cũng đang cần giải cái này bằng VBA áp dụng cho tình huống của mình à! @thao nguyen01
 
Upvote 0
Bạn đã có kết quả chưa bạn, mình đã cũng đang cần giải cái này bằng VBA áp dụng cho tình huống của mình @thao nguyen01

@hoangtuchanlon Mình cũng chưa có kết quả bài này bạn, hiện giờ mình cũng đang làm tình huống này bằng thủ công vì khi mình chạy solver, nhiều biến quá solver không ra kết quả bạn. Còn code VBA trên hình như kết quả ra sai bạn.
 
Upvote 0
@hoangtuchanlon Mình cũng chưa có kết quả bài này bạn, hiện giờ mình cũng đang làm tình huống này bằng thủ công vì khi mình chạy solver, nhiều biến quá solver không ra kết quả bạn. Còn code VBA trên hình như kết quả ra sai bạn.
Vậy à, mình thì mới biết VBA có mấy ngày, đặt câu lệnh nhưng nó lâu quá, mãi không ra nên mới nhà diễn đàn xem có ai gặp tình huống này chưa. hix
 
Upvote 0
Vậy à, mình thì mới biết VBA có mấy ngày, đặt câu lệnh nhưng nó lâu quá, mãi không ra nên mới nhà diễn đàn xem có ai gặp tình huống này chưa. hix

Mình cũng vậy, bài này code VBA mình nghĩ cũng không ra, khi gặp bài này mình dùng solver trước, nhưng do dữ liệu mình nhiều nên khi solver không ra kết quả luôn. Mình dò thủ công thì mất nhiều thời gian
 
Upvote 0
Bài này khoảng 50 số thì mình làm thử ok rồi nhưng chỉ là hệ số bằng 0 hay 1 thôi. Của bạn hoàng tử chăn lợn là từ 0 đến 5 thì chưa biết có chạy nổi không.
 
Upvote 0
Bài này khoảng 50 số thì mình làm thử ok rồi nhưng chỉ là hệ số bằng 0 hay 1 thôi. Của bạn hoàng tử chăn lợn là từ 0 đến 5 thì chưa biết có chạy nổi không.

Dạ, bài của em chỉ là 0 và 1 ạ. Sau đó em dùng Sumproduct, nếu thỏa yêu cầu là đúng ạ. Nhưng đối với dữ liệu trên anh có ra không ạ. Vì em chạy solver không ra ạ?
 
Upvote 0
Bài này khoảng 50 số thì mình làm thử ok rồi nhưng chỉ là hệ số bằng 0 hay 1 thôi. Của bạn hoàng tử chăn lợn là từ 0 đến 5 thì chưa biết có chạy nổi không.
bạn dịch hay quá, tôi thì gặp mấy cái từ lẩn quẩn ở chỗ "lon" là tôi hết suy nghĩ :p
Hồi xưa tôi tính lấy tên ChoLon nhưng sợ thiên hạ hiểu lầm.
 
Upvote 0
Dạ, bài của em chỉ là 0 và 1 ạ. Sau đó em dùng Sumproduct, nếu thỏa yêu cầu là đúng ạ. Nhưng đối với dữ liệu trên anh có ra không ạ. Vì em chạy solver không ra ạ?
Mình làm được khoảng 50 70 số nguyên còn số thực thì chạy cũng có thể ra nhưng chưa chắc chắn do khi so sánh 2 số thực nhìn giống nhau nhưng thực tế vẫn không bằng.
 
Upvote 0
Web KT

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

Back
Top Bottom