Giúp hộ về thuật giải! bài toán chia kẹo (1 người xem)

  • Thread starter Thread starter ThuNghi
  • Ngày gửi Ngày gửi
Liên hệ QC

Người dùng đang xem chủ đề này

ThuNghi

Hãy cho rồi sẽ nhận!
Thành viên đã mất
Tham gia
16/8/06
Bài viết
3,808
Được thích
4,449
Tôi có bài tóan về chia như sau:
+ Tôi và 2 người bạn gồm 3 (bên cho) người ủng hộ 4 em thiếu nhi tổng cộng số kẹo cho là 100 theo chi tiết.
- C01: 20
- C02: 30
- C03: 50
+ Cùng chia cho 4 em thiếu nhi (bên nhận) với sl không đều nhau và các em đã nhận theo chi tiết.
- N01: 40
- N02: 36
- N03: 5
- N04: 19
Nhờ các bác làm giúp hộ thuật giải về chia thế nào mà phân bổ số kẹo bên cho -> bên nhận, cụ thể như sau:
- C01/N01: 20*40/100; C01/N02: 5*40/100 ... (bình quân)
- C01/N01: 20; C02/N01: 20...
Cụ thể theo file, tôi có làm bài tóan phân bổ đều nhưng không xử lý được số lẻ.
Rất cám ơn, nếu được cho xin cách bằng VBA, vì số người cho và số người nhận thay đổi chỉ tuân thủ nguyên tắc là TS cho = TS nhận.
Đang cần khá gấp. Xin cám ơn nhiều!
Bài tóan này cũng giống như dạng bài tóan kế tóan nhiều nợ và nhiều có như ví dụ:
N641: 50; N642: 35: N621: 15; N627: 20
C111: 20: C141: 45: C331:55
Vậy làm sao chia lại theo cặp TK Nợ-Có: tiền
Không quan tâm là chi từ nguồn nào miễn sao khớp thôi. Bài tóan chữa cháy.
 

File đính kèm

Thu Nghi à, nếu là chia kẹo thì theo phương án 2 được, vì kẹo nào cũng là kẹo,vì nguời nào chia lẻ thì dồn cho nguời chia lẻ khác chia đến hêt. Nhưng theo ví dụ về TK thì không được vì còn liên quan tới cơ cấu chi phí từng đối tượng. Không thể đối tượng này tỷ lệ chi phí tiền lương cao hơn đối tượng khác.Không thể dồn số lẻ tiền lương sang để chia thành CPQL được

Điểm mấu chốt ở đây là khả năng đồng quy hay không?
 
Thu Nghi à, nếu là chia kẹo thì theo phương án 2 được, vì kẹo nào cũng là kẹo,vì nguời nào chia lẻ thì dồn cho nguời chia lẻ khác chia đến hêt. Nhưng theo ví dụ về TK thì không được vì còn liên quan tới cơ cấu chi phí từng đối tượng. Không thể đối tượng này tỷ lệ chi phí tiền lương cao hơn đối tượng khác.Không thể dồn số lẻ tiền lương sang để chia thành CPQL được

Điểm mấu chốt ở đây là khả năng đồng quy hay không?
Rất cám ơn anh, không quan trọng về cơ cấu, có thể cặp đó vô lý nhưng trong những cặp đó hóan vị cho nhau sẽ có cái có lý, đã lỡ rồi, khi trích lọc sẽ có soct. Có thể chỉ là C111N911 (ví dụ) cũng không ảnh hưởng. P/ án 2 có thể thêm bớt không cố định.
Bác cố gắng giúp em nhé. Cứ coi như là chia kẹo (nguyên viên) as long.
Mấy Bác đang liệt kê số ĐT bỏ chút time giúp bài này hộ. Hậu tạ 1 chầu bia Ken chay. Còn ở xa thì hẹn dịp nào đó.
 
Mình nghĩ mãi cũng chỉ có phương án 1 của bạn là hợp lý chứ chia keo nguyên chiếc thì vô lý lắm, sau này khi giải trình cơ cấu mệt lắm.
 
Mình nghĩ mãi cũng chỉ có phương án 1 của bạn là hợp lý chứ chia keo nguyên chiếc thì vô lý lắm, sau này khi giải trình cơ cấu mệt lắm.
Nhưng phương án 1 lại bị số lẻ và quan trọng nhất là số dòng bị nhân lên rất nhiều. Vậy anh làm hộ em PA1 cũng được, nếu có thể anh cho em code hơn 1 lần chia ie lần 1 3 chia cho 4, tiếp tục 5 chia cho 3. Bác bịa thêm cho em.
Cám ơn anh.
Em đã trả lời anh Sealand qua tín nhắn.
 
Bạn có thể xin thêm danh mục TK (TK trực tiếp) được không, nếu được thì viết hàm trả về TK nợ, TK có cho từng dòng có được không.? KHi đã rõ định khoản từng dòng là bạn sử lý tốt rồi
 
Đối với dạng bài toán phân phối không đòi hỏi cao thì có thể dùng Solver để giải, chỉ với lưu ý: vì là bài toán nguyên, nên chọn mô hình tuyến tính để giải. Sau khi tìm được nghiệm có thể save thành 1 kịch bản để so sánh với lần giải kế tiếp để chọn ra giải pháp tốt hơn.
Ví dụ, với dữ liệu mẫu có thể chọn được phưong án sau:
Số tiền c01 c02 c03 40 15 24 1 5 3 1 1 36 1 1 34 19 1 4 14 100 20 30 50
 
Lần chỉnh sửa cuối:
Đối với dạng bài toán phân phối không đòi hỏi cao thì có thể dùng Solver để giải, chỉ với lưu ý: vì là bài toán nguyên, nên chọn mô hình tuyến tính để giải. Sau khi tìm được nghiệm có thể save thành 1 kịch bản để so sánh với lần giải kế tiếp để chọn ra giải pháp tốt hơn.
Ví dụ, với dữ liệu mẫu có thể chọn được phưong án sau:

Số tiền c01 c02 c03
40 15 24 1
5 3 1 1
36 1 1 34
19 1 4 14

100 20 30 50


Đúng rồi dùng solver và có nhiều phương án

C01 C02 C03
20 30 50
N01 40 1 27 12
N02 5 1 1 3
N03 36 17 1 18
N04 19 1 1 17
C01 C02 C03
20 30 50
N01 40 17 9 14
N02 5 1 3 1
N03 36 1 1 34
N04 19 1 17 1


C01 C02 C03
20 30 50
N01 40 1 9 30
N02 5 1 3 1
N03 36 17 1 18
N04 19 1 17 1

v v .......

* Có thể dùng VBA liệt kê ra tất cả các phương án
 
Đối với dạng bài toán phân phối không đòi hỏi cao thì có thể dùng Solver để giải, chỉ với lưu ý: vì là bài toán nguyên, nên chọn mô hình tuyến tính để giải. Sau khi tìm được nghiệm có thể save thành 1 kịch bản để so sánh với lần giải kế tiếp để chọn ra giải pháp tốt hơn.
Ví dụ, với dữ liệu mẫu có thể chọn được phưong án sau:
Số tiền c01 c02 c03 40 15 24 1 5 3 1 1 36 1 1 34 19 1 4 14 100 20 30 50
Chỉ cần 1 phương án thôi, nhờ Luân viết giúp 1 code nhé. Cám ơn nhiều!
Từ nguồn trên tạo ra như file
C01---N01--ST
...
Nếu có thể cho thêm 1 lần chia theo tiêu thức trên nhưng làm 2 lần, xem như 2 lần chia khác nhau. Lần 1: 3 chia cho 4, lần 2: 5 chia cho 2. Luân triển khai tiếp 1 ví dụ.
 
Em không hiểu gì về nghiệp vụ kế toán nên không biết về tài khoản nợ - có gì cả. Bác thử dùng đoạn code trong file này xem sao. Hy vọng đúng ý bác.
 

File đính kèm

Phân Phối

Bác cũng có thể xem thêm cách phân phối trong file đính kèm.
 

File đính kèm

Từ sang dến giờ bận không lên mạng được, vấn đề của Thu Nghi chỉ dùng công thức không ổn vì nó phức tạp.Đêm qua xem, nhưng vẫn chưa nghĩ cách sử lý thỏa đáng. Ví dụ của Thu NGhi chỉ là 1 trong n nhóm chia và nhận kẹo. Một trường hợp của ví dụ thì đôi khi ta không hiểu tại sao việc đơn giản chỉ việc làm tròn 1 chút là được. Nhưng với vài chục ngàn nhóm như ví dụ thì chỉ có Auto thôi, chứ sức nào mà soát xét.

Vấn đề ở đây như Thu Nghi nói là tìm ra phương án chia cho n nhóm chia và nhận kẹo và gần như không nhóm nào giống nhóm nào.Cái khó là chia không chặt đôi ba kẹo ra. Các bác giỏi VBA cố gắng giúp dân kế toán chúng tôi với, đây là một bài toán rất thiết thực.

To Hoang Vu Luan: Bạn nghiên cứu giùm dùng biện pháp sử lý của bạn áp dụng cho n nhóm và các nhóm hoàn toàn khác nhau.
rollover79: Code của bạn khá khả quan đấy, bạn xem phát triển thêm trong trường hợp n nhóm.
 
Lần chỉnh sửa cuối:
Làm rõ thêm về ví dụ của Thu Nghi: Các bạn xem nội dung trong File
Phương án mình đề xuất thêm trong file nhằm gỡ thế không thể chia do lẻ quá
 

File đính kèm

Lần chỉnh sửa cuối:
rollover79: Code của bạn khá khả quan đấy, bạn xem phát triển thêm trong trường hợp n nhóm.
Code của tôi xử lý động theo các vùng được định nghĩa thông qua Name. Ở đây tôi định nghĩa ra 3 Name là.
- Cho: Vùng định nghĩa nhóm các bên cho(Gồm 2 cột: Tên và Số lượng cho).
- Nhan: Vùng định nghĩa nhóm các bên nhận(Gồm 2 cột: Tên và Số lượng nhận).
- KetQua: Vùng chứa kết quả(Gồm 3 cột: Tên bên cho, Tên bên nhận, Số lượng).
Vậy muốn có bao nhiêu nhóm thì chỉ cần định nghĩa mở rộng các Name ra là ok thôi.
 
Rất cám ơn các Bác, các phương pháp giải tuyệt vời. Đang nghiên cứu code của Rollover79 để triển khai theo ý mình. Cám ơn rất nhiều. Cái ví dụ của mình là giống như ví dụ mà Bác Sealand đưa lên. Để mình tự mày mò triển khai thử, có gí sẽ nhờ tiếp.
Mốt lần nữa xin cám ơn: Sealand, Hoangvuluan, Rollover79, Tigertiger. Quan trọng là giúp mình được thuật giải.
Có chuyện làm chiều thứ 7. Chúc các Bác cuối tuần vui vẻ, phải chi ở gần nhỉ. Hình như mỗi người 1 tỉnh: HP, TTH, HN, ...đại ca này giờ chả biết ở đâu!
 
Tôi triển khai code của RollOver79 để làm thử với # 400 nhóm và 1000 record. Nhưng còn 1 vấn đề này cần hỏi,
- Đối với quan hệ x Cho, y Nhận, x và y >1:dùng code này.
- Đối với quan hệ x Cho, y Nhận, x = 1 và y >=1 hoặc y = 1 và x >=1, trường hợp này mình có cần thiết phải làm thêm một nhánh If để giảm thiểu số lần tính Do...While.
Các Bác test thử code và cho lời khuyên.
Xin cám ơn!
PHP:
Dim rngCho As Range, rngNhan As Range, rngKetQua As Range
Dim curCho As Double, curNhan As Double, curSLCho As Double, curSLNhan As Double
Dim curSLChoDu As Double, curSLNhanThieu As Double, iRow As Double, SLChia As Double
Dim endR As Double, rngData As Range, rngDMCT As Range
Dim WF As WorksheetFunction
Dim Dem As Long, dongDau As Long
Public sSoCT As String
Sub TaoKQ()
With Application
  .ScreenUpdating = False: .DisplayAlerts = False: .Calculation = xlCalculationManual
End With
SortData
TaoRng
With Application
  .ScreenUpdating = True: .DisplayAlerts = True: .Calculation = xlCalculationAutomatic
End With
End Sub
Sub SortData()
Sheets("Data").Select
endR = [A65000].End(xlUp).Row
Set rngData = Range("A1:D" & endR)
With Sheets("Tmp")
  .[A1:I65000].ClearContents
  .Range("A1:D" & endR) = rngData.Value
  Set rngData = .Range("A1:D" & endR)
End With
With rngData
  .Sort Key1:=.Cells(1, 1), Order1:=xlAscending, Key2:=.Cells(1, 3) _
        , Order2:=xlAscending, Key3:=.Cells(1, 4), Order3:=xlAscending, Header:= _
        xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _
        DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, DataOption3:= _
        xlSortNormal
End With
Set rngData = rngData.Resize(, 1)
Sheets("DMCT").[A1:A65000].ClearContents
With rngData
  .AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Sheets("DMCT").Range( _
        "A1"), Unique:=True
End With
With Sheets("DMCT")
  .Names("Extract").Delete
End With
Set rngData = Nothing
End Sub
Sub TaoRng()
Set WF = WorksheetFunction
With Sheets("KQ")
  .[A2:I65000].ClearContents
End With
With Sheets("DMCT")
  endR = .[A65000].End(xlUp).Row
  Set rngDMCT = .Range(.Cells(2, 1), .Cells(endR, 1))
End With
With Sheets("Tmp")
  endR = .[A65000].End(xlUp).Row
  Set rngData = .Range("A2:A" & endR)
  For iCT = 1 To rngDMCT.Rows.Count
    sSoCT = rngDMCT(iCT, 1)
    dongDau = WF.Match(sSoCT, rngData, 0)
    Dem = WF.CountIf(rngData, sSoCT)
    Set rngCho = rngData.Offset(dongDau - 1, 2).Resize(Dem, 1)
    Set rngCho = rngCho.SpecialCells(xlCellTypeConstants, 23)
    Set rngCho = rngCho.Offset(, -1).Resize(, 2)
    Set rngNhan = rngData.Offset(dongDau - 1, 3).Resize(Dem, 1)
    Set rngNhan = rngNhan.SpecialCells(xlCellTypeConstants, 23)
    Set rngNhan = rngNhan.Offset(, -2).Resize(, 3)
    GanKQ
  Next
End With
End Sub
Sub GanKQ()
curCho = 0
curNhan = 0
With Sheets("KQ")
  iRow = .[A65000].End(xlUp).Row + 1
  Do While Not (curCho = rngCho.Rows.Count And curSLChoDu = 0)
    If curSLChoDu = 0 Then
      curCho = curCho + 1
      curSLCho = rngCho(curCho, 2)
      curSLChoDu = curSLCho
    End If
    If curSLNhanThieu = 0 Then
      curNhan = curNhan + 1
      curSLNhan = rngNhan(curNhan, 3)
      curSLNhanThieu = curSLNhan
    End If
    SLChia = IIf(curSLChoDu <= curSLNhanThieu, curSLChoDu, curSLNhanThieu)
    .Cells(iRow, 1) = sSoCT
    .Cells(iRow, 2) = rngCho(curCho, 1)
    .Cells(iRow, 3) = rngNhan(curNhan, 1)
    .Cells(iRow, 4) = SLChia
    curSLChoDu = curSLChoDu - SLChia
    curSLNhanThieu = curSLNhanThieu - SLChia
    iRow = iRow + 1
  Loop
End With
End Sub
Code khá vụng về, các Bác tối ưu hộ luôn.
 

File đính kèm

- Đối với quan hệ x Cho, y Nhận, x và y >1:dùng code này.
- Đối với quan hệ x Cho, y Nhận, x = 1 và y >=1 hoặc y = 1 và x >=1, trường hợp này mình có cần thiết phải làm thêm một nhánh If để giảm thiểu số lần tính Do...While.
Tôi đã thêm If để tách riêng các quan hệ trên cho chạy nhanh hơn.
Các bạn có thể triển khai code này để tạo nhật ký chung (NKC) từ nhật ký chung (NKC) theo ý muốn để có thể tạo sổ cái. Do có những PM khi trích xuất theo dạng
TKĐƯ ----Số Tiền Nợ---Số tiền Có
..............................................
Thành dạng
TK Nợ---TK Có---Số tiền
 

File đính kèm

Lần chỉnh sửa cuối:
Em xin góp ý một chút, bác không cần tách thêm 2 trường hợp x=1 và y=1 đâu, cái vòng lặp của em bắt đầu xuất phát từ 0(2 cái biết curCho và curNhan được gán =0 trước khi vào vòng lặp), và nó lặp cho đến hết thì thôi, vậy x và y bằng bao nhiêu thì số vòng lặp cũng không hề thay đổi. Bác có thể dùng Debug để kiểm chứng là số vòng lặp không khác nhau trong 2 trường hợp viết code.
 
Em xin góp ý một chút, bác không cần tách thêm 2 trường hợp x=1 và y=1 đâu, cái vòng lặp của em bắt đầu xuất phát từ 0(2 cái biết curCho và curNhan được gán =0 trước khi vào vòng lặp), và nó lặp cho đến hết thì thôi, vậy x và y bằng bao nhiêu thì số vòng lặp cũng không hề thay đổi. Bác có thể dùng Debug để kiểm chứng là số vòng lặp không khác nhau trong 2 trường hợp viết code.
Do thấy việc thêm vài dòng code cũng đơn giản và thấy có vẻ nhanh hơn thì thêm luôn. Mặc dù code của bạn đã duyệt từ đầu. Tôi thấy nếu x=1 or y=1 thì trước hết khỏi dùng iif và phép trừ để xác định SLChia. Cứ nghĩ vậy nên tách luôn. Cám ơn Rollover nhiều. Thuật giải trên giúp tôi khối việc.
 
Em không hiểu gì về nghiệp vụ kế toán nên không biết về tài khoản nợ - có gì cả. Bác thử dùng đoạn code trong file này xem sao. Hy vọng đúng ý bác.
Bác RollOver79 giúp hộ triển khai bài tóan trên.
Nếu tòan bộ SL chia là số âm thì nên sửa code thế nào.
Đính kèm file yêu cầu.
Nhờ Bác giúp hộ.

Xin cám ơn!

Bổ sung thêm, không phải lúc nào cũng số âm. Và thêm trường hợp số có 2 số lẻ, khi chia thường thêm các dòng =0 -> SlChia=0.
 

File đính kèm

Lần chỉnh sửa cuối:
Web KT

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

Back
Top Bottom