Lập trình công thức điền chỉnh hợp chập Chữ X bằng VBA (1 người xem)

Liên hệ QC

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

thungdols

Thành viên chính thức
Tham gia
27/3/09
Bài viết
66
Được thích
2
Em có một bài toán khó là lập các hàng chỉnh hợp chập của 5 chữ X vào 12 ô sao cho các dòng không trùng nhau. Cái này à viết tày thì mất 792 dòng kiểu này thì chết em mất. Mong các bac giúp đỡ+-+-+-++-+-+-++-+-+-+
 
Xin lỗi, minh hiểu nhầm. Nhờ MOD xoá giùm.
 
Lần chỉnh sửa cuối:
Đây là cách thông dụng nhất, xin mại zô!

PHP:
Option Explicit
Sub ChinhHopChap5Cua12()
 Const GPE12 As String = "A12B3456C7890"
 Dim j1 As Byte, J2 As Byte, J3 As Byte, J4 As Byte, J5 As Byte
 For j1 = 1 To 12
   For J2 = j1 + 1 To 12
      For J3 = J2 + 1 To 12
         For J4 = J3 + 1 To 12
            For J5 = J4 + 1 To 12
               With [A65500].End(xlUp).Offset(1)
                  .Value = Mid(GPE12, j1, 1) & Mid(GPE12, J2, 1) & Mid(GPE12, J3, 1) _
                     & Mid(GPE12, J4, 1) & Mid(GPE12, J5, 1)
               End With
 Next J5, J4, J3, J2, j1
End Sub
 
Lần chỉnh sửa cuối:
PHP:
Option Explicit
Sub ChinhHopChap5Cua12()
Const GPE12 As String = "A12B3456C7890"
Dim j1 As Byte, J2 As Byte, J3 As Byte, J4 As Byte, J5 As Byte
For j1 = 1 To 12
For J2 = j1 + 1 To 12
For J3 = J2 + 1 To 12
For J4 = J3 + 1 To 12
For J5 = J4 + 1 To 12
With [A65500].End(xlUp).Offset(1)
.Value = Mid(GPE12, j1, 1) & Mid(GPE12, J2, 1) & Mid(GPE12, J3, 1) _
& Mid(GPE12, J4, 1) & Mid(GPE12, J5, 1)
End With
Next J5, J4, J3, J2, j1
End Sub
Hix ! Bác làm ơn xem lại hộ em một chút nhé. Bác thông cảm là nhập vào từng ô chứ không phải nhập vào cùng 1 ô đâu.
 
Nó nhập vô cột A mà; Nếu cột này đang trống, nó sẽ nhập từ [A2] cho tới [A793];
Muốn chạy lần nữa nó sẽ chép tiếp sau ô cuối đó, trừ fi bạn chịu khó xóa cột dữ liệu cũ đi sau mỗi lần thử nghiệm!

Thân ái!
 
Hix ! Bác làm ơn xem lại hộ em một chút nhé. Bác thông cảm là nhập vào từng ô chứ không phải nhập vào cùng 1 ô đâu.
Chài ai...
Tách ra dể mà bạn (làm bằng tay cũng được)
Còn không thì vầy đi
PHP:
Sub ChinhHopChap5Cua12()
  Const GPE12 As String = "A12B3456C7890"
  Dim j1 As Byte, J2 As Byte, J3 As Byte, J4 As Byte, J5 As Byte, i As Long
  For j1 = 1 To 12
    For J2 = j1 + 1 To 12
      For J3 = J2 + 1 To 12
        For J4 = J3 + 1 To 12
          For J5 = J4 + 1 To 12
            With [A1:E1].Offset(i)
              .Value = Array(Mid(GPE12, j1, 1), Mid(GPE12, J2, 1), Mid(GPE12, J3, 1), _
                       Mid(GPE12, J4, 1), Mid(GPE12, J5, 1))
              i = i + 1
           End With
  Next J5, J4, J3, J2, j1
End Sub
 
Hix ! Bác làm ơn xem lại hộ em một chút nhé. Bác thông cảm là nhập vào từng ô chứ không phải nhập vào cùng 1 ô đâu.
Thuật toán là vậy, khi sử dụng bạn phải biết tùy biến chứ.
PHP:
Option Explicit
Sub ChinhHopChap5Cua12()
Dim j1 As Byte, J2 As Byte, J3 As Byte, J4 As Byte, J5 As Byte, i As Integer, Rng As Range
Set Rng = [A1]
For j1 = 1 To 12
    For J2 = j1 + 1 To 12
        For J3 = J2 + 1 To 12
            For J4 = J3 + 1 To 12
                For J5 = J4 + 1 To 12
                    i = i + 1
                    Set Rng = Union(Rng, Cells(i, j1), Cells(i, J2), Cells(i, J3), Cells(i, J4), Cells(i, J5))
Next J5, J4, J3, J2, j1
Rng.Value = "x"
End Sub
 
Thuật toán là vậy, khi sử dụng bạn phải biết tùy biến chứ.
PHP:
Option Explicit
Sub ChinhHopChap5Cua12()
Dim j1 As Byte, J2 As Byte, J3 As Byte, J4 As Byte, J5 As Byte, i As Integer, Rng As Range
Set Rng = [A1]
For j1 = 1 To 12
    For J2 = j1 + 1 To 12
        For J3 = J2 + 1 To 12
            For J4 = J3 + 1 To 12
                For J5 = J4 + 1 To 12
                    i = i + 1
                    Set Rng = Union(Rng, Cells(i, j1), Cells(i, J2), Cells(i, J3), Cells(i, J4), Cells(i, J5))
Next J5, J4, J3, J2, j1
Rng.Value = "x"
End Sub
Xem chừng việc "thu gom" toàn bộ các cell rồi gán giá trị 1 lần cho tốc độ làm việc chậm hơn thì phải
Cái này nhanh hơn:
PHP:
Sub Test1()
  Dim j1 As Long, J2 As Long, J3 As Long, J4 As Long, J5 As Long, i As Long
  Dim TG As Double
  TG = Timer
  For j1 = 1 To 12
    For J2 = j1 + 1 To 12
      For J3 = J2 + 1 To 12
        For J4 = J3 + 1 To 12
          For J5 = J4 + 1 To 12
            i = i + 1
            Union(Cells(i, j1), Cells(i, J2), Cells(i, J3), Cells(i, J4), Cells(i, J5)) = "x"
  Next J5, J4, J3, J2, j1
  MsgBox Timer - TG
End Sub
Tốc độ cực nhanh... gần như ra kết quả trong tức khắc
 
Xem chừng việc "thu gom" toàn bộ các cell rồi gán giá trị 1 lần cho tốc độ làm việc chậm hơn thì phải
Cái này nhanh hơn:
PHP:
Sub Test1()
  Dim j1 As Long, J2 As Long, J3 As Long, J4 As Long, J5 As Long, i As Long
  Dim TG As Double
  TG = Timer
  For j1 = 1 To 12
    For J2 = j1 + 1 To 12
      For J3 = J2 + 1 To 12
        For J4 = J3 + 1 To 12
          For J5 = J4 + 1 To 12
            i = i + 1
            Union(Cells(i, j1), Cells(i, J2), Cells(i, J3), Cells(i, J4), Cells(i, J5)) = "x"
  Next J5, J4, J3, J2, j1
  MsgBox Timer - TG
End Sub
Tốc độ cực nhanh... gần như ra kết quả trong tức khắc
Cũng dễ hiểu thôi. Trong quá trình xử lý code phải lưu một biến nhớ có dung lượng lớn (biến Rng) làm tốc độ chậm lại. Tuy nhiên, để chắc ăn phải set Calculation = Manual trước. Chạy code của bạn trong khi đang mở một file làm việc khác thời gian là 50s. Do mỗi lần gán giá trị vào cell. Các công thức lại tính toán lại một lần. Ngoài ra, các biến j1, j2,... chỉ có giá trị từ 1 đến 12 thì nên khai báo kiểu Byte là hợp lý, biến i chỉ cần kiểu Integer là đủ. Tiết kiệm tài nguyên sẽ cải thiện tốc độ.
Kiểu dữ liệu | Kích thước
Byte| 1 byte
Integer| 2 byte
Long| 4 byte
PHP:
Sub ChinhHopChap5Cua12()
Dim j1 As Byte, J2 As Byte, J3 As Byte, J4 As Byte, J5 As Byte, i As Integer, Rng As Range
Application.Calculation = xlCalculationManual
For j1 = 1 To 12
    For J2 = j1 + 1 To 12
        For J3 = J2 + 1 To 12
            For J4 = J3 + 1 To 12
                For J5 = J4 + 1 To 12
                    i = i + 1
                    Union(Cells(i, j1), Cells(i, J2), Cells(i, J3), Cells(i, J4), Cells(i, J5)).Value = "x"
Next J5, J4, J3, J2, j1
Application.Calculation = xlCalculationAutomatic
End Sub
 
Chổ nào cũng đúng, trừ chổ này:
Ngoài ra, các biến j1, j2,... chỉ có giá trị từ 1 đến 12 thì nên khai báo kiểu Byte là hợp lý, biến i chỉ cần kiểu Integer là đủ. Tiết kiệm tài nguyên sẽ cải thiện tốc độ.
Biến Long mới là đúng nhất và tiết kiệm nhất
 
Lần chỉnh sửa cuối:
Bạn có thể cho mọi người biết nguyên nhân vì sao không?
Cái này đã thuộc về "chân lý" mà cả Bill và các cao thủ trên toàn thế giới đều công nhận (tưởng bạn đã đọc qua bài viết trên GPE rồi chứ)
Có thể diển giải ngắn gọn thế này: Dù rằng ta có đặt biến Byte hay Integer thì trong quá trình làm việc nó cũng sẽ được chuyển thành biến Long (chuyển xong mới làm việc)
Vì thế thay vì khai báo Byte hay Integer, ta khai báo luôn là Long (đở tốn công bác Bill)
Đã từ lâu lắm rồi, tôi quên luôn thằng ByteInteger, cứ Long cho chắc bắp (trừ những trường hợp đặc biệt...)
Thông tin:
[B đã viết:
Dailydose[/B]]...If you use the Integer data type in your code, Excel will convert it to a Long, so you might as well just use Long. It still produces an overflow error if you get outside the Integer bounds, I’ve noticed..
[B đã viết:
msdn.microsoft.com[/B]]
...The Integer and Long data types can both hold positive or negative values. The difference between them is their size: Integer variables can hold values between -32,768 and 32,767, while Long variables can range from -2,147,483,648 to 2,147,483,647. Traditionally, VBA programmers have used integers to hold small numbers, because they required less memory. In recent versions, however, VBA converts all integer values to type Long, even if they are declared as type Integer. Therefore, there is no longer a performance advantage to using Integer variables; in fact, Long variables might be slightly faster because VBA does not have to convert them...
 
Lần chỉnh sửa cuối:
Cái này đã thuộc về "chân lý" mà cả Bill và các cao thủ trên toàn thế giới đều công nhận (tưởng bạn đã đọc qua bài viết trên GPE rồi chứ)
Có thể diển giải ngắn gọn thế này: Dù rằng ta có đặt biến Byte hay Integer thì trong quá trình làm việc nó cũng sẽ được chuyển thành biến Long (chuyển xong mới làm việc)
Vì thế thay vì khai báo Byte hay Integer, ta khai báo luôn là Long (đở tốn công bác Bill)
Đã từ lâu lắm rồi, tôi quên luôn thằng ByteInteger, cứ Long cho chắc bắp (trừ những trường hợp đặc biệt...)
Thông tin:
Thì ra là vậy. Từ trước đến giờ tôi cứ ngỡ Excel mượn ngôn ngữ của VB thì cũng nó cũng mang tất cả các đặc điểm của VB chứ. Đúng là sai lầm thật.
 
Về lí thì mình đồng í với NDU; Nhưng về tình thì còn lăng tăng nhiều lắm!

Thứ nhất, sao có nó mà không xài;
Nên xài nó/chúng vào những việc như:

Khi không muốn xài số âm, tôi cứ Byte mà tương, một khi nó còn trong fép;
Hay những lúc khi mà tốc độ không là vấn đề gì thật sự lớn lao (Như không fải xữ những CSDL lớn, . . . ) mình cũng chiếu cố đến các anh này

Còn làm việc với các cột trang tính (E2K3) mình toàn xài kiểu dữ liệu Byte; Thật ra mình cũng không biết tại sao làm vậy; Chắc tại thói quen mà thôi;

Xin mời các bạn nào rỗi ta thử chạy macro này xem sao:

PHP:
Option Explicit
Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
Sub MmM()
 Dim jJ As Byte, Ww As Byte, Kk As Byte
 Dim Zz As Long, Ff As Long, iI As Long
 Dim Timer_ As Double
 
 Timer_ = GetTickCount
 For jJ = 1 To 250
   Do
      Ww = Ww + 2:      Ww = Ww - 1
      If Ww > 250 Then
         Kk = Kk + 1:   Ww = 1
         Sleep 1
      End If
      If Kk > 254 Then Exit For
   Loop
 Next jJ
 [A65500].End(xlUp).Offset(1).Value = GetTickCount - Timer_
 
  Timer_ = GetTickCount
  For Zz = 1 To 250
   Do
      Ff = Ff + 2:      Ff = Ff - 1
      If Ff > 250 Then
         iI = iI + 1:   Ff = 1
         Sleep 1
      End If
      If iI > 254 Then Exit For
   Loop
 Next Zz
  [b65500].End(xlUp).Offset(1).Value = GetTickCount - Timer_
 
End Sub
 
Thứ nhất, sao có nó mà không xài;
Nên xài nó/chúng vào những việc như:

Khi không muốn xài số âm, tôi cứ Byte mà tương, một khi nó còn trong fép;
Điều này đương nhiên sư phụ à! Bởi vậy ở trên em có nói rằng:
Đã từ lâu lắm rồi, tôi quên luôn thằng ByteInteger, cứ Long cho chắc bắp (trừ những trường hợp đặc biệt...)
Có 1 vài đoạn code em vẫn buộc phải dùng biến Byte ---> Mà cùng lắm cũng chỉ dùng ByteLong, chứ Integer thì hầu như em "quăng" luôn (vì nó thuộc cái hệ dở dở ương ương)
 
Em có một bài toán khó là lập các hàng chỉnh hợp chập của 5 chữ X vào 12 ô sao cho các dòng không trùng nhau. Cái này à viết tày thì mất 792 dòng kiểu này thì chết em mất. Mong các bac giúp đỡ+-+-+-++-+-+-++-+-+-+
Các trả lời và con số 792 ở trên dường như là tính tổ hợp chập 5 của 12.
 
Xin mời các bạn nào rỗi ta thử chạy macro này xem sao:
PHP:
Option Explicit
Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
Sub MmM()
 Dim jJ As Byte, Ww As Byte, Kk As Byte
 Dim Zz As Long, Ff As Long, iI As Long
 Dim Timer_ As Double
 
 Timer_ = GetTickCount
 For jJ = 1 To 250
   Do
      Ww = Ww + 2:      Ww = Ww - 1
      If Ww > 250 Then
         Kk = Kk + 1:   Ww = 1
         Sleep 1
      End If
      If Kk > 254 Then Exit For
   Loop
 Next jJ
 [A65500].End(xlUp).Offset(1).Value = GetTickCount - Timer_
 
  Timer_ = GetTickCount
  For Zz = 1 To 250
   Do
      Ff = Ff + 2:      Ff = Ff - 1
      If Ff > 250 Then
         iI = iI + 1:   Ff = 1
         Sleep 1
      End If
      If iI > 254 Then Exit For
   Loop
 Next Zz
  [b65500].End(xlUp).Offset(1).Value = GetTickCount - Timer_
 
End Sub
Xin bàn ngoài lề 1 chút về đoạn code trên!
- Hàm GetTickCount là dùng để lấy số milliseconds tính từ khi Windows khởi động đến thời điểm hiện tại
- Trong đoạn code trên có 2 điểm em không hiểu (về ý đồ của sư phụ)
Thứ nhất: Tại sao Ww = Ww + 2 rồi lại Ww = Ww - 1 mà không là Ww = Ww +1 ???
Thứ hai: Vòng lập For trong code trên em chẳng hiểu dùng để làm gì ---> Vì ở giữa chẳng có chổ nào tính toán với biến chạy jJ Zz? ---> Tức là vào vòng lập For.. Next, đến Do.. Loop làm việc rồi Exit For luôn (vòng lập For chẳng có cơ hội để chạy tiếp lần 2)
- Có vẽ như code dùng để tính thời gian chạy của 1 đoạn code (tính bằng ms)
 
còn với trường hợp lấy 5 cột trong 400 cột thì như thế nào vậy các bác. giúp em với @@
thanks nhiu nhìu
 

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

Back
Top Bottom