如何使用VBA生成52卡组的所有4种卡组合?

时间:2018-02-20 10:18:28

标签: excel vba excel-vba combinatorics

我正在尝试使用一副52张牌生成4张牌的所有组合。生成所有排列将很容易(和长),但在卡片中,顺序无关紧要,所以例如Ah,Kh,Qh,Jh将与Kh,Ah,Qh,Jh相同。有人能指出我正确的方向或向我展示一些我可以使用的示例代码吗?发现很奇怪,之前没人试过。

5 个答案:

答案 0 :(得分:3)

使用4个嵌套循环。为了防止重复并且仅计算“唯一集合”,我认为您必须从每个循环开始:[the 'parent' loop's current value] + 1

这是代码:

Option Explicit

Sub All4Combos()

    'Caution!  Save your work before runnning! (or set constant smaller)

    Const NumCardsInDeck = 52
    Dim c1, c2, c3, c4
    Dim p As Long

    For c1 = 1 To NumCardsInDeck
        For c2 = c1 + 1 To NumCardsInDeck
            For c3 = c2 + 1 To NumCardsInDeck
               For c4 = c3 + 1 To NumCardsInDeck

                    p = p + 1
                    Debug.Print c1, c2, c3, c4

                Next c4
            Next c3
        Next c2
    Next c1

    Debug.Print p & " Combinations of " & NumCardsInDeck & " cards"

End Sub

结果:

排列数量:

52 x 51 x 50 x 49

组合数量:

Permuations / slots!
--OR--
(52 x 51 x 50 x 49) / (4 x 3 x 2 x 1)

结果是270725种组合。

以下是10张卡的结果集:

1,2,4,10
1,2,5,6
1,2,5,7
1,2,5,8
1,2,5,9
1,2,5,10
1,2,6,7
1,2,6,8
1,2,6,9
1,2,6,10
1,2,7,8
1,2,7,9
1,2,7,10
1,2,8,9
1,2,8,10
1,2,9,10
1,3,4,5
1,3,4,6
1,3,4,7
1,3,4,8
1,3,4,9
1,3,4,10
1,3,5,6
1,3,5,7
1,3,5,8
1,3,5,9
1,3,5,10
1,3,6,7
1,3,6,8
1,3,6,9
1,3,6,10
1,3,7,8
1,3,7,9
1,3,7,10
1,3,8,9
1,3,8,10
1,3,9,10
1,4,5,6
1,4,5,7
1,4,5,8
1,4,5,9
1,4,5,10
1,4,6,7
1,4,6,8
1,4,6,9
1,4,6,10
1,4,7,8
1,4,7,9
1,4,7,10
1,4,8,9
1,4,8,10
1,4,9,10
1,5,6,7
1,5,6,8
1,5,6,9
1,5,6,10
1,5,7,8
1,5,7,9
1,5,7,10
1,5,8,9
1,5,8,10
1,5,9,10
1,6,7,8
1,6,7,9
1,6,7,10
1,6,8,9
1,6,8,10
1,6,9,10
1,7,8,9
1,7,8,10
1,7,9,10
1,8,9,10
2,3,4,5
2,3,4,6
2,3,4,7
2,3,4,8
2,3,4,9
2,3,4,10
2,3,5,6
2,3,5,7
2,3,5,8
2,3,5,9
2,3,5,10
2,3,6,7
2,3,6,8
2,3,6,9
2,3,6,10
2,3,7,8
2,3,7,9
2,3,7,10
2,3,8,9
2,3,8,10
2,3,9,10
2,4,5,6
2,4,5,7
2,4,5,8
2,4,5,9
2,4,5,10
2,4,6,7
2,4,6,8
2,4,6,9
2,4,6,10
2,4,7,8
2,4,7,9
2,4,7,10
2,4,8,9
2,4,8,10
2,4,9,10
2,5,6,7
2,5,6,8
2,5,6,9
2,5,6,10
2,5,7,8
2,5,7,9
2,5,7,10
2,5,8,9
2,5,8,10
2,5,9,10
2,6,7,8
2,6,7,9
2,6,7,10
2,6,8,9
2,6,8,10
2,6,9,10
2,7,8,9
2,7,8,10
2,7,9,10
2,8,9,10
3,4,5,6
3,4,5,7
3,4,5,8
3,4,5,9
3,4,5,10
3,4,6,7
3,4,6,8
3,4,6,9
3,4,6,10
3,4,7,8
3,4,7,9
3,4,7,10
3,4,8,9
3,4,8,10
3,4,9,10
3,5,6,7
3,5,6,8
3,5,6,9
3,5,6,10
3,5,7,8
3,5,7,9
3,5,7,10
3,5,8,9
3,5,8,10
3,5,9,10
3,6,7,8
3,6,7,9
3,6,7,10
3,6,8,9
3,6,8,10
3,6,9,10
3,7,8,9
3,7,8,10
3,7,9,10
3,8,9,10
4,5,6,7
4,5,6,8
4,5,6,9
4,5,6,10
4,5,7,8
4,5,7,9
4,5,7,10
4,5,8,9
4,5,8,10
4,5,9,10
4,6,7,8
4,6,7,9
4,6,7,10
4,6,8,9
4,6,8,10
4,6,9,10
4,7,8,9
4,7,8,10
4,7,9,10
4,8,9,10
5,6,7,8
5,6,7,9
5,6,7,10
5,6,8,9
5,6,8,10
5,6,9,10
5,7,8,9
5,7,8,10
5,7,9,10
5,8,9,10
6,7,8,9
6,7,8,10
6,7,9,10
6,8,9,10
7,8,9,10
210 Combinations of 10 cards

答案 1 :(得分:1)

为了它的乐趣

基于ashleedawg的代码并将结果写入文本文件我得到了这个结果:

Run took 2293 milliseconds
Wrote cardcombos.txt with 270725 lines of 4-card combinations of totally 52 cards

将代码移植到C ++产生了这个:

Run took 203 milliseconds
Wrote cardcombos.txt with 270725 lines of 4-card combinations of totally 52 cards

答案 2 :(得分:0)

这基本上是“多少握手”问题的扩展版本......

有几种方法可以解决这个问题 - 一种方法是强制它(生成所有排列,将所有元素分类为卡/套装顺序,然后删除重复项)

第二个选项是创建一个套牌并按顺序处理(“卡1可以与卡2配对 - 52,对1&2可以使用卡片3 - 52,三位一体1&2&3可以使用卡片4 - 52“对其进行整理,然后从卡片中移除”已用过的“卡片用于下一个循环的堆栈(“triad 1&2&4可以使用卡5 - 52进行四舍五入,对1&3可以使用卡4 - { {1}},卡52可以与卡2 - 3配对。“这将在四重奏52停止

而且,是的,您的工作簿需要很长时间才能完成这些工作。只要完整的6,497,400个排列,但仍然有270,725个组合。

答案 3 :(得分:0)

对上面提供的代码进行了一些更改。这是最终结果。

Option Explicit

Sub All4Combos()

Dim Cards() As String

'Caution!  Save your work before runnning! (or set constant smaller)

Cards = Split("As,Ks,Qs,Js,Ts,9s,8s,7s,6s,5s,4s,3s,2s,Ah,Kh,Qh,Jh,Th,9h,8h,7h,6h,5h,4h,3h,2h,Ad,Kd,Qd,Jd,Td,9d,8d,7d,6d,5d,4d,3d,2d,Ac,Kc,Qc,Jc,Tc,9c,8c,7c,6c,5c,4c,3c,2c", ",")
Const NumCardsInDeck = 51
Dim c1, c2, c3, c4
Dim p As Long
p = 0
For c1 = 0 To NumCardsInDeck
    For c2 = c1 + 1 To NumCardsInDeck
        For c3 = c2 + 1 To NumCardsInDeck
           For c4 = c3 + 1 To NumCardsInDeck

                p = p + 1
                Cells(p, 1) = Cards(c1) & Cards(c2) & Cards(c3) & Cards(c4)

            Next c4
        Next c3
    Next c2
Next c1


End Sub

答案 4 :(得分:0)

如果我们将卡片拆分为4件套装,每件都有13张卡片并以此作为我们的基础,则有4种卡片的5种不同组合可以撤销,如果我们只将套装作为唯一性:< / p>

  • ♥♦♣♠ - 四种不同的诉讼
  • ♥♦♣♣ - 三种不同的诉讼
  • ♣♣♥♥ - 两种不同的西装(2:2)
  • ♣♣♣♥ - 两种不同的西装(3:1)
  • ♥♥♥♥ - 仅限一件西装

现在,差不多,如果为所有套装模拟所有这些可能性,5次模拟的总和应该等于(49x50x51x52)/(4x3x2)= 270725

♥♦♣♠

For cnt1 = 1 To totalCards
    For cnt2 = 1 To totalCards
        For cnt3 = 1 To totalCards
            For cnt4 = 1 To totalCards
                numberResult = numberResult + 1
            Next : Next : Next : Next

四个嵌套循环正是所需要的。对于每件套装,totalCards=13numberResult*4,我们会获得 28561 。或13^4

♥♦♣♣

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cntA = 1 To 3
            For cnt3 = 1 To totalCards
                For cnt4 = 1 To totalCards
                    numberResult = numberResult + 1
                Next : Next : Next : Next : Next

这里的想法是,对于同一套装的每两张牌,有一套,在我们的计算中不会发生。因此,cntA = 1 To 3。最后,我们为每件套装乘以4以获得 158184

♣♣♥♥

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cnt3 = 1 To totalCards
            For cnt4 = cnt3 + 1 To totalCards
                numberResult = numberResult + 1
            : Next : Next : Next : Next

我们有78种可能来自同一套装的2张牌。这是使用前两个嵌套循环进行模拟的。另外两种颜色的78种可能性是接下来的2个嵌套循环。因此,我们有6084种变体。然而,将4个套装组合成2个联合的方法是6(♥♣,♥♦,♥♠,♣♦,♣♠,♦♠),因此我们将结果乘以6得到 36504

♣♣♣♥

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cnt3 = cnt2 + 1 To totalCards
            For cnt4 = 1 To totalCards
                numberResult = numberResult + 1
            Next : Next : Next : Next

这里我们有3张相同的牌和一张不同牌。每1套3张相同的卡,我们可能有3张不同的卡。我们有4套西装,因此,我们必须乘以12(4x3)才能获得 44616

♥♥♥♥

For cnt1 = 1 To totalCards
    For cnt2 = cnt1 + 1 To totalCards
        For cnt3 = cnt2 + 1 To totalCards
            For cnt4 = cnt3 + 1 To totalCards
                numberResult = numberResult + 1
            Next : Next : Next : Next

这与接受的答案完全一样,但在这种情况下我们totalCards = 13。至于我们有4种不同的套装,我们乘以4得到 2860

这是代码的结果:

 28561  4 different suits.
158184  3 different suits.
 36504  2(2:2) different suits.
 44616  2(3:1) different suits.
  2860  1 suit only.
270725  All.270725

最后,代码来了:

Public Sub TestMe()

    Dim cnt1&, cnt2&, cnt3&, cnt4&, cntA&
    Dim totalCards&: totalCards = 13
    Dim numberResult&, totalResult&

    '4 different suits
    For cnt1 = 1 To totalCards
        For cnt2 = 1 To totalCards
            For cnt3 = 1 To totalCards
                For cnt4 = 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult
    Debug.Print " " & numberResult & vbTab & "4 different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '3 different suits
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cntA = 1 To 3
                For cnt3 = 1 To totalCards
                    For cnt4 = 1 To totalCards
                        numberResult = numberResult + 1
                    Next: Next: Next: Next: Next
    numberResult = numberResult * 4
    Debug.Print numberResult & vbTab & "3 different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '2 different suits (2+2)
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cnt3 = 1 To totalCards
                For cnt4 = cnt3 + 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult * 6
    Debug.Print " " & numberResult & vbTab & "2(2:2) different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '2 different suits (3+1)
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cnt3 = cnt2 + 1 To totalCards
                For cnt4 = 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult * 12
    Debug.Print " " & numberResult & vbTab & "2(3:1) different suits."
    totalResult = numberResult + totalResult
    numberResult = 0

    '1 different suit
    For cnt1 = 1 To totalCards
        For cnt2 = cnt1 + 1 To totalCards
            For cnt3 = cnt2 + 1 To totalCards
                For cnt4 = cnt3 + 1 To totalCards
                    numberResult = numberResult + 1
                Next: Next: Next: Next
    numberResult = numberResult * 4
    Debug.Print "  " & numberResult & vbTab & "1 suit only."
    totalResult = numberResult + totalResult
    numberResult = 0

    Debug.Print totalResult & vbTab & "All." & (49& * 50 * 51 * 52) / (4 * 3 * 2)

End Sub