代表5张扑克牌


11

一副牌是52张。一手是52张牌中的5张(不能重复)。

代表5张牌的最小位数是多少?如何?
一手不依赖于顺序(KQ = QK)。64329 = 96432

是的,可以使用52位。那可以代表任意数量的卡牌。

给定一手牌正好是5张牌,有一种方法可以用少于52位来表示它。

一张卡可以用6位= 64表示。所以可以只用6位* 5张卡= 30位。但这将取决于订单。我可以排序,这应该可以工作。如果那行不通,请告诉我。

有没有一种方法可以使密钥达到32位或以下,而不必对5卡元组进行排序。

这是用于扑克模拟,而与仅产生一手牌相比,分类会产生很多开销。如果我有一本具有每只手的相对值的字典,则它是两个简单的查找和一个比较以比较两只手的值的比较。如果我必须先对手进行排序,那将比两次查找和比较要大。在模拟中将比较数百万。我不会从模拟中得到排序。排序并不像52 51 50 49 47之前的52 51 50 49 48那样简单。您可以使用直冲四边形....

有2598960张可能的5张牌。那就是行数。关键是5张卡。我想要一个32位或以下的卡密钥,不需要先对卡进行排序。

不能只订购尽可能多的领带。西装是锹,棍棒,钻石和心脏。7c 8c 2d 3d 4s = 7s 8s 2c 3c 4h。有很多联系。

下一步是64位,它将接受排序,而不是密钥大小的两倍。

我测试SortedSet<int> quickSort = new SortedSet<int>() { i, j, k, m, n };了手术时间并使其加倍,但是我仍然可以这样做。

它变得更加复杂。我需要能够将船表示为五分之二(22255)。因此,对它们进行分类就可以了。我知道你会说,但这很快。是的,它既快速又琐碎,但我需要尽可能快。

C#接受的答案:

private int[] DeckXOR = new int[] {0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
                                    0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
                                    0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
                                    0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
                                    0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
                                    0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
                                    0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
                                    0x04878b06,0x069b3c05,0x054089a3};
public void PokerProB()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    HashSet<int> cardsXOR = new HashSet<int>();
    int cardXOR;
    int counter = 0;
    for (int i = 51; i >= 4; i--)
    {
        for (int j = i - 1; j >= 3; j--)
        {
            for (int k = j - 1; k >= 2; k--)
            {
                for (int m = k - 1; m >= 1; m--)
                {
                    for (int n = m - 1; n >= 0; n--)
                    {
                        counter++;
                        cardXOR = DeckXOR[i] ^ DeckXOR[j] ^ DeckXOR[k] ^ DeckXOR[m] ^ DeckXOR[n];
                        if (!cardsXOR.Add(cardXOR))
                            Debug.WriteLine("problem");
                    }
                }
            }
        }
    }
    sw.Stop();
    Debug.WriteLine("Count {0} millisec {1} ", counter.ToString("N0"), sw.ElapsedMilliseconds.ToString("N0"));
    Debug.WriteLine("");
}

4
使用可用于对长度为5的列表进行排序的手工编码排序算法。这可能比您当前正在使用的库函数更快。
Yuval Filmus

1
我不明白您为什么说“排序不简单”。排序简单-将每张卡转换为1到52之间的数字,以便用一张(长度为5)的卡列表来表示手。对该列表进行排序。正如Yuval提到的那样,这只是对5个整数列表进行排序的问题,可以很快完成。我建议您在假设它太慢之前进行测量,但是我猜想对这样一个列表进行排序将非常快,甚至可能比未在缓存中命中的随机存取存储器读取更快。
DW

@dw是的,排序很简单,但是我正在做的事情(数百万次)很简单。我测试了一下,时间翻了一番。
paparazzo

1
@Paparazzi不,Yuval告诉您编写自己的排序例程,该例程专门调整为对1到52之间的五个数字进行排序。您尝试使用库例程,这很慢,因为它比这更通用,并且具有递归性质quicksort的功能使它在短名单上的效率很低。
David Richerby

实际上,大多数不小于16位的项目也可能是32位。因此,由于您至少需要23位,因此使用<= 32位的任何编码可能都是可行的。每张卡琐碎的6位* 5卡编码效果很好。有一个警告:23位数组索引比32位数组索引好得多。
MSalters'Apr

Answers:


10

C[52,25,11]C27×521152A1,,A52Ai271100a,b,c,d,eAaAbAcAdAeH1,H2102|H1H2|10

鲍勃·詹金斯(Bob Jenkins)在他的网站中描述了这样的代码,从中我们可以提取数组

0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
0x04878b06,0x069b3c05,0x054089a3

252271=2251


我不完全了解。一只手需要多少位?
paparazzo

它需要27位。您可以使用更多位数。
Yuval Filmus

谢谢。我测试过,数字是唯一的,且<= 32位。我可以从号码中得出5张卡吗?如果不是很好,那就问。
paparazzo

是的,它是简单的线性代数。您可以使用正确的矩阵取回5个长度为52的向量。我让你知道。
Yuval Filmus

13

nlgnlg2598960=22

表示如何工作?有多种选择,具有不同的权衡。我在下面列出两个。

硬编码字典

在这种情况下,可能的5张牌的手的数量足够少,以至于您只能拥有列出所有2598960手的硬编码字典,并且您可以通过其在字典中的索引来代表一手(以二进制表示)。

换句话说,字典可以是手的排序列表。每手是按顺序排列的手牌中的5元组。您可以使用二进制搜索在字典中查找一手,并找到其相应的索引;并给定索引,您可以找到对应的手。或者,您可以将字典存储为从手映射到其索引的哈希图。索引是0到2598959之间的整数,因此可以使用23位表示。

这种方法可以工作并且编程非常简单,但是在空间(程序可执行文件的大小)方面是浪费的。

排名/排名

另外,如果您愿意,还有更好的方法。参见,例如,以下任何参考文献:

一般主题称为“组合的排名(和取消排名)”。这些实现和理解起来有些复杂,但是避免了在程序中包含硬编码字典的需求。


我将更新问题。是的,共有2598960手。字典将有那么多行。我的问题是密钥的生成。从5张卡中,我需要生成一个密钥以执行字典查找。
狗仔队

@狗仔队,如果您使用字典方法,那么手就是关键。换句话说,关键是手中的五元组(按排序顺序)。可以使用该字典作为键将其存储为哈希表。如果您不喜欢字典的存储成本,请使用另一种方法:排名/不排名。
DW

是的,我知道排序后可以得到30位的密钥。我想知道是否有一种方法可以不对5卡元组进行排序就获得32位或以下的密钥。我将研究排名和排名。
paparazzo

我不关注排名/排名,但谢谢。我会尝试解决。也有联系的可能性。有很多联系。
paparazzo


3

您可以对这五个项目进行排序,并在不进行任何比较的情况下同时检查重复项,而无需对某些处理器进行任何比较:假设处理器具有一条快速指令(该指令确定最高位集的位置)和一条快速指令(仅计算第n个位集) 。

设(n)位为正好设置了第n位的数字。令maximum_bit(x)为数字x中设置的最高位的数字,如果x = 0,则未指定值。令x ^ y为x和y的异或。

给出五个数字a,b,c,d和e,每个数字从0到51,代表手中的五张牌。

令x =位(a)^位(b)^位(c)^位(d)^位(e)。

设A = maximum_bit(x),将x更改为x ^ bit(A)。

令B = maximum_bit(x),将x更改为x ^ bit(B)。

令C = maximum_bit(x),将x更改为x ^ bit(C)。

令D = maximum_bit(x),将x更改为x ^ bit(D)。

令E = maximum_bit(x)。

如果x = 0,则数字a,b,c,d和e中有重复项。否则,使用A *位(24)+ B *位(18)+ C *位(12)+ D *位(6)+ E作为手的编码,其中A,B,C,D和E为手如上定义。这会将手编码为30位字符串,同时以非常有效的方式进行排序。


这会使用52位吗?
paparazzo

@狗仔队,不。再看最后一段。我对其进行了编辑,以试图提供更大的清晰度。
DW

1
它需要64位CPU,但最终结果仅为30位。
Yuval Filmus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.