{非技术}斗地主游戏中地主手中牌出现至少一个非王炸的概率是多少

108 views
Skip to first unread message

十年磨剑

unread,
Nov 30, 2009, 9:27:03 AM11/30/09
to TopLanguage
不知道大家玩过斗地主游戏没有,做个简要介绍吧:
一副牌(54张),3个人玩,其中一个人(地主)拿20张牌,另外两个人(农民)分别拿17张;
拿到4张点数一样的为炸,大小王在一起也成炸(俗称火箭);
我数学不好,想请教一下大家,地主拿到至少一个非火箭的炸概率有多少?

MadCow

unread,
Nov 30, 2009, 9:55:56 PM11/30/09
to pon...@googlegroups.com
20/52 * 19/51 * 18/50 * 17/49?

2009/11/30 十年磨剑 <beiji...@hotmail.com>

Patrol Sun

unread,
Dec 1, 2009, 4:25:45 AM12/1/09
to pon...@googlegroups.com
程序模拟好像是19%左右

2009/12/1 MadCow <cai.zh...@gmail.com>

十年磨剑

unread,
Dec 1, 2009, 10:02:22 AM12/1/09
to TopLanguage
我要一个理论值,我想是不是13*(50张牌选16)/(54张牌选20)?
理由是总数为54张牌选20张,然后有13种可能的炸,每种炸有50张牌选16张剩余可能;

On 12月1日, 下午5时25分, Patrol Sun <sunp1...@gmail.com> wrote:
> 程序模拟好像是19%左右
>
> 2009/12/1 MadCow <cai.zhaohu...@gmail.com>


>
> > 20/52 * 19/51 * 18/50 * 17/49?
>

> > 2009/11/30 十年磨剑 <beijingc...@hotmail.com>

fansong zeng

unread,
Dec 1, 2009, 2:46:58 AM12/1/09
to pon...@googlegroups.com
可以用DP求解,思路是这样的:
设一个非王炸都没有的概率为p,则所求概率为1-p。
54张牌中选20张有C(54, 20)种选法,那么只需求一个非王炸都没有拿到的可能性有多少种。
先按其手中的王的个数分三类 A B C;
A 一个王都没有:
用ai表示其手中排i(i={1,2,3,4,5,6,7,8,9,10,J,Q,K}的张数),则一个炸弹没有的可能性为以下方程解的数目:
a1+a2+...+a13 = 20   ai = {0,1,2,3}
用N[k,m] 表示 a1+a2+...+ak = m的解的数目
则N[k,m] = N[k-1,m] + N[k-1,m-1] + N[k-1,m-2] + N[k-1,m-3];
初始条件: N[1,i] = 1, i = {0,1,2,3}
               N[1,i] = 0, else
解为 N[13,20]
B 有一个王
解为 2*N[13,19]
C 有两个王
解为 N[13,18]

所以最后得到 p = ( N[13,20] + 2*N[13,19] + N[13,18] )/C(54,20)
再用1减之得 斗地主游戏中地主手中牌出现至少一个非王炸的概率
2009/12/1 MadCow <cai.zh...@gmail.com>

fansong zeng

unread,
Dec 1, 2009, 8:21:14 AM12/1/09
to pon...@googlegroups.com
如下描述才准确:
用N[k,m]表示从{1,2,3,4,5,6,7,8,9,10,J,Q,K}的前k种牌中选m张的种类
考虑第k种排选0,1,2,3张的情况有:
N[k,m] = N[k-1,m] + 4*N[k-1,m-1] + 6*N[k-1,m-2] + 4*N[k-1,m-3];
初始条件也变了,见如下C++代码
//注:本来想用TMP求C(54,20),无奈enum是32位的int型,要溢出
#include <iostream>

typedef __int64 longlong;
typedef unsigned __int64 ulonglong;
const int X = 14;
const int Y = 21;

template <unsigned M,unsigned N>
struct combination {
    enum { value = combination<M-1,N-1>::value + combination<M-1,N>::value };
};
template <unsigned M>
struct combination<M,M> {
    enum { value = 1 };
};
template <unsigned M>
struct combination<M,0> {
    enum { value = 1 };
};

int main() {
    longlong N[X][Y] = {0};
    N[1][0] = 1;
    N[1][1] = 4;
    N[1][2] = 6;
    N[1][3] = 4;
    for (int i=4; i < Y; ++i) {
        N[1][i] = 0;
    }
    for (int i=1; i < X; ++i) {
        longlong t = 2*i;
        N[i][0] = 1;
        N[i][1] = 2*t;
        N[i][2] = (N[i][1]-1)*t;
    }
    for (int x=2; x < X; ++x) {
        for (int y=3; y < Y; ++y) {
            N[x][y] = N[x-1][y] + 4*N[x-1][y-1] + 6*N[x-1][y-2] + 4*N[x-1][y-3];
        }
    }

    longlong comb[55][21] = {0};
    for (int i=1; i < 55; ++i) {
        comb[0][i] = 0;
    }
    for (int i=0; i < 21; ++i) {
        comb[i][0] = 1;
    }
    for (int i=1; i < 55; ++i) {
        for (int j=1; j < 21; ++j) {
            comb[i][j] = comb[i-1][j-1] + comb[i-1][j];
        }
    }

    longlong c = N[13][20] + 2*N[13][19] + N[13][18];
    longlong b = comb[54][20];
    double p = static_cast<double>(c)/b;
    std::cout << (1-p)*100 << "%\n";
    return 0;
}

结果手中至少一个非王炸的概率为: 18.9821%。
2009/12/1 fansong zeng <fans...@gmail.com>
二楼的方案有点问题, 不好意思

2009/12/1 Patrol Sun <sunp...@gmail.com>

fansong zeng

unread,
Dec 1, 2009, 10:41:49 AM12/1/09
to pon...@googlegroups.com
至少一个炸弹不是恰有一个炸弹,你题意描述的意思就是我上面的解法。
理论值也是一大堆的 ∑ ,不会简单到哪去的。
这题不用计算机估计很能算出来吧。

2009/12/1 十年磨剑 <beiji...@hotmail.com>

fansong zeng

unread,
Dec 1, 2009, 9:27:55 PM12/1/09
to pon...@googlegroups.com
5楼代码依然有bug。。。 最后是:18.9823%
下面的没有问题了:
//注:C++0x支持64位的enum,另外VC里面也支持。

#include <iostream>

typedef __int64 longlong;
typedef unsigned __int64 ulonglong;
const int X = 14;
const int Y = 21;

template <unsigned M,unsigned N>
struct combination {
    enum :__int64 { value = combination<M-1,N-1>::value + combination<M-1,N>::value };

};
template <unsigned M>
struct combination<M,M> {
    enum :__int64 { value = 1 };

};
template <unsigned M>
struct combination<M,0> {
    enum :__int64 { value = 1 };

};

int main() {
    longlong N[X][Y] = {0};
    N[1][0] = 1;
    N[1][1] = 4;
    N[1][2] = 6;
    N[1][3] = 4;
    for (int i=4; i < Y; ++i) {
        N[1][i] = 0;
    }
    for (int i=1; i < X; ++i) {
        longlong t = 2*i;
        N[i][0] = 1;
        N[i][1] = 2*t;
        N[i][2] = (N[i][1]-1)*t;
    }
    for (int x=2; x < X; ++x) {
        for (int y=3; y < Y; ++y) {
            N[x][y] = N[x-1][y] + 4*N[x-1][y-1] + 6*N[x-1][y-2] + 4*N[x-1][y-3];
        }
    }

    longlong comb[55][21] = {0};
    for (int i=1; i < 21; ++i) {

        comb[0][i] = 0;
    }
    for (int i=0; i < 55; ++i) {

        comb[i][0] = 1;
    }
    for (int i=1; i < 55; ++i) {
        for (int j=1; j < 21; ++j) {
            comb[i][j] = comb[i-1][j-1] + comb[i-1][j];
        }
    }

    longlong c = N[13][20] + 2*N[13][19] + N[13][18];
    longlong b = static_cast<unsigned __int64>(combination<54,20>::value);

    double p = static_cast<double>(c)/b;
    std::cout << (1-p)*100 << "%\n";
    return 0;
}

2009/12/1 fansong zeng <fans...@gmail.com>

pengfei yu

unread,
Dec 1, 2009, 11:04:33 PM12/1/09
to pon...@googlegroups.com
我认为13*(50张牌选16)/(54张牌选20)不对,比较笨的方法:分类讨论,地主可以拿到炸的可能:
5个炸:(13张选5张)
4个炸:(13张选4张),还有4张的情况,
都不同,9张选4张;
2张相同,(9张选2张)*7*6;
3张相同,(9张选1张)*8;
3个炸:同理
2009/12/1 十年磨剑 <beiji...@hotmail.com>

十年磨剑

unread,
Dec 2, 2009, 10:06:26 AM12/2/09
to TopLanguage
OK,明白你的意思了,用递归的思路是没有问题的;
但是我没怎么想清楚我的解法哪里有问题,我的想法是先固定住一个炸,这样有13种方式,
那剩下的只能从50张牌里选择16张牌,问题在哪呢?

> 2009/12/1 fansong zeng <fanste...@gmail.com>
>
> > 二楼的方案有点问题, 不好意思[?]
>
> > 2009/12/1 Patrol Sun <sunp1...@gmail.com>
>
> > 程序模拟好像是19%左右
>
> >> 2009/12/1 MadCow <cai.zhaohu...@gmail.com>


>
> >>> 20/52 * 19/51 * 18/50 * 17/49?
>

> >>> 2009/11/30 十年磨剑 <beijingc...@hotmail.com>


>
> >>> 不知道大家玩过斗地主游戏没有,做个简要介绍吧:
> >>>> 一副牌(54张),3个人玩,其中一个人(地主)拿20张牌,另外两个人(农民)分别拿17张;
> >>>> 拿到4张点数一样的为炸,大小王在一起也成炸(俗称火箭);
> >>>> 我数学不好,想请教一下大家,地主拿到至少一个非火箭的炸概率有多少?
>
>
>

> 323.gif
> < 1K查看下载

十年磨剑

unread,
Dec 2, 2009, 10:07:20 AM12/2/09
to TopLanguage
很想知道为什么13*C(50,16)/ C(54,20)不对?

On 12月2日, 下午12时04分, pengfei yu <asd...@gmail.com> wrote:
> 我认为13*(50张牌选16)/(54张牌选20)不对,比较笨的方法:分类讨论,地主可以拿到炸的可能:
> 5个炸:(13张选5张)
> 4个炸:(13张选4张),还有4张的情况,
> 都不同,9张选4张;
> 2张相同,(9张选2张)*7*6;
> 3张相同,(9张选1张)*8;
> 3个炸:同理

> 2009/12/1 十年磨剑 <beijingc...@hotmail.com>

十年磨剑

unread,
Dec 2, 2009, 10:58:41 AM12/2/09
to TopLanguage
我知道我的问题在哪里了,我把排列和组合弄混了;
其实并不仅仅是13*C(50,16),因为每一个炸弹在20张牌中出现的次序有很多种,所以需要乘上那些种类;
也就是说,是13 * C(50,16)* (4张牌落在20张牌中的总可能数)= 13 * C(50, 16) * 24 * (4个相同球落在
20个洞的总可能数)
这样我算出来的值为16.596785%,怎么算出来的不一样?这次又错了吗?
唉,实在是搞不了数学。

十年磨剑

unread,
Dec 2, 2009, 11:02:16 AM12/2/09
to TopLanguage
更正,算出来是19.916143%。

fansong zeng

unread,
Dec 1, 2009, 5:56:31 AM12/1/09
to pon...@googlegroups.com
二楼的方案有点问题, 不好意思

2009/12/1 Patrol Sun <sunp...@gmail.com>
程序模拟好像是19%左右

fansong zeng

unread,
Dec 2, 2009, 10:37:19 AM12/2/09
to pon...@googlegroups.com
固定一个炸弹,然后再选16张的问题在于:
固定A时选16张 和 固定B时选16张 之间有交集
讨论交集 固定AB时,选其它的,又和固定CD时选其它的又有交集,依次下去复杂度可想而知
所以只能讨论一个炸弹都拿不到的情况。
OK?

2009/12/2 十年磨剑 <beiji...@hotmail.com>

十年磨剑

unread,
Dec 2, 2009, 10:29:13 PM12/2/09
to TopLanguage
恩,明白了。十分感谢

On 12月2日, 下午11时37分, fansong zeng <fanste...@gmail.com> wrote:
> 固定一个炸弹,然后再选16张的问题在于:
> 固定A时选16张 和 固定B时选16张 之间有交集
> 讨论交集 固定AB时,选其它的,又和固定CD时选其它的又有交集,依次下去复杂度可想而知
> 所以只能讨论一个炸弹都拿不到的情况。
> OK?
>

> 2009/12/2 十年磨剑 <beijingc...@hotmail.com>

dean zhang

unread,
Dec 2, 2009, 11:30:30 PM12/2/09
to pon...@googlegroups.com
提供一个思路,根据抽签等概率的原理,那么每人每次抽到一张特定牌的概率应该是相等的(为1/54),我的思路也是基于这一点的。
分析可以取到四张1的情况,设概率为p,则取不到四张1的概率为1-p,其它同理;
可知1到K都取不到四张的概率为(1-p)^13,那么所求即为1-(1-p)^13。问题转换为对p的求解。

四张1的概率p是否可以这样考虑:20次中每次取黑桃1的概率都为1/54,20次中按序取黑、红、方、草的概率为(1/54)^4,一共有20选4种这样按序取的可能,而且取花色的可能有4!种(此处有简单问题复杂化之嫌,请见谅)。即取四张1的概率p为:P(20,4) * (1/54)^4

我算出的结果大概是16.4%
有不当之处,希望各位批评指正。

Wooddy

unread,
Dec 4, 2009, 2:37:40 AM12/4/09
to TopLanguage
fansong的结果是正确的,这题也可以用生成函数解。

没有非王炸的生成函数为:
(x^0+4x^1+6x^2+4x^3)^13(x^0+2x^1+x^2)
其中x^20的系数为:260380724617728

任意选取的生成函数为:
(x^0+4x^1+6x^2+4x^3+x^4)^13(x^0+2x^1+x^2)
其中x^20的系数为:321387366339585

于是概率p = 1 - 260380724617728/321387366339585 = 0.1898

虽然生成函数的展开也很麻烦(可以用mathematica),但是能给出解这类题的一类通用手段。


On 12月3日, 下午12时30分, dean zhang <seds19841...@gmail.com> wrote:
> 提供一个思路,根据抽签等概率的原理,那么每人每次抽到一张特定牌的概率应该是相等的(为1/54),我的思路也是基于这一点的。
> 分析可以取到四张1的情况,设概率为p,则取不到四张1的概率为1-p,其它同理;
> 可知1到K都取不到四张的概率为(1-p)^13,那么所求即为1-(1-p)^13。问题转换为对p的求解。
>

> 四张1的概率p是否可以这样考虑:20次中每次取黑桃1的概率都为1/54,20次中按序取黑、红、方、草的概率为(1/54)^4,一共有20选4种这样按序-取的可能,而且取花色的可能有4!种(此处有简单问题复杂化之嫌,请见谅)。即取四张1的概率p为:P(20,4)


> * (1/54)^4
>
> 我算出的结果大概是16.4%
> 有不当之处,希望各位批评指正。
> --

> msn:seds-19841...@hotmail.com <msn%3Aseds-19841...@hotmail.com>
> Gwave:seds19841...@googlewave.com <Gwave%3Aseds19841...@googlewave.com>
> twitter:twitter.com/seds19841231
> QQ:seds19841...@126.com <QQ%3Aseds19841...@126.com>

fansong zeng

unread,
Dec 3, 2009, 1:41:54 AM12/3/09
to pon...@googlegroups.com
看上面我的代码吧,最终答案是 18.9823%
其实转化后就是一个数学上叫数列问题,计算机里我们叫DP(动态规划)问题。

2009/12/3 dean zhang <seds19...@gmail.com>

Wooddy

unread,
Dec 4, 2009, 2:58:05 AM12/4/09
to TopLanguage

> 没有非王炸的生成函数为:
> (x^0+4x^1+6x^2+4x^3)^13(x^0+2x^1+x^2)
> 其中x^20的系数为:260380724617728
>
> 任意选取的生成函数为:
> (x^0+4x^1+6x^2+4x^3+x^4)^13(x^0+2x^1+x^2)
> 其中x^20的系数为:321387366339585 ********* 呃,其实就是C(54, 20),这式子多余了,一时写顺手了。

>
> 于是概率p = 1 - 260380724617728/321387366339585 = 0.1898
>
> 虽然生成函数的展开也很麻烦(可以用mathematica),但是能给出解这类题的一类通用手段。
>
> On 12月3日, 下午12时30分, dean zhang <seds19841...@gmail.com> wrote:
>
>
>
> > 提供一个思路,根据抽签等概率的原理,那么每人每次抽到一张特定牌的概率应该是相等的(为1/54),我的思路也是基于这一点的。
> > 分析可以取到四张1的情况,设概率为p,则取不到四张1的概率为1-p,其它同理;
> > 可知1到K都取不到四张的概率为(1-p)^13,那么所求即为1-(1-p)^13。问题转换为对p的求解。
>
> > 四张1的概率p是否可以这样考虑:20次中每次取黑桃1的概率都为1/54,20次中按序取黑、红、方、草的概率为(1/54)^4,一共有20选4种这样按序--取的可能,而且取花色的可能有4!种(此处有简单问题复杂化之嫌,请见谅)。即取四张1的概率p为:P(20,4)

> > * (1/54)^4
>
> > 我算出的结果大概是16.4%
> > 有不当之处,希望各位批评指正。
> > --
> > msn:seds-19841...@hotmail.com <msn%3Aseds-19841...@hotmail.com>
> > Gwave:seds19841...@googlewave.com <Gwave%3Aseds19841...@googlewave.com>
> > twitter:twitter.com/seds19841231
> > QQ:seds19841...@126.com <QQ%3Aseds19841...@126.com>- 隐藏被引用文字 -
>
> - 显示引用的文字 -

obtuseSword

unread,
Dec 4, 2009, 9:19:24 AM12/4/09
to TopLanguage
也可以用容斥原理: C(13,1) C(50,16) - C(13,2) C(46,12) + C(13,3) C(42,8) - C
(13,4) C(38,4) + C(13,5) C(34,0) = 22670621227 / 119430459435 ≈
0.1898227750

On Dec 3, 2:41 pm, fansong zeng <fanste...@gmail.com> wrote:
> 看上面我的代码吧,最终答案是 18.9823%
> 其实转化后就是一个数学上叫数列问题,计算机里我们叫DP(动态规划)问题。
>

> 2009/12/3 dean zhang <seds19841...@gmail.com>


>
> > 提供一个思路,根据抽签等概率的原理,那么每人每次抽到一张特定牌的概率应该是相等的(为1/54),我的思路也是基于这一点的。
> > 分析可以取到四张1的情况,设概率为p,则取不到四张1的概率为1-p,其它同理;
> > 可知1到K都取不到四张的概率为(1-p)^13,那么所求即为1-(1-p)^13。问题转换为对p的求解。
>
> > 四张1的概率p是否可以这样考虑:20次中每次取黑桃1的概率都为1/54,20次中按序取黑、红、方、草的概率为(1/54)^4,一共有20选4种这样按序取的可能,而且取花色的可能有4!种(此处有简单问题复杂化之嫌,请见谅)。即取四张1的概率p为:P(20,4)
> > * (1/54)^4
>
> > 我算出的结果大概是16.4%
> > 有不当之处,希望各位批评指正。
> > --

cui nk

unread,
Dec 5, 2009, 7:56:11 AM12/5/09
to TopLanguage
对的,容斥原理是最优雅的理论解啦

bookcpp

unread,
Feb 1, 2010, 6:38:51 AM2/1/10
to pon...@googlegroups.com

0.19916142557652
 
(13*c(50,16)*(34,17)*(17,17)) / ((54,20)*(34,17)*(17,17))

bookcpp

unread,
Feb 1, 2010, 6:54:29 AM2/1/10
to pon...@googlegroups.com
就当做一个简单的概率题就可以了。
 
出现炸的有13种可能,
 
比如是四个 1
a:地主 共有20张牌
b,c :各有17张
 
第一步算 当地主拿四个一的可能的 个数 从(54-4)种取(20-4)张,再b从剩下的34种选取17张,最后c从17张中选取最后的17张。
总的次数是才:: na = c(50,16)*c(34,17)*c(17,17)
 
同理第二步   计算分牌的所有可能数 N=c(54,20)*c(34,17)*c(17,17)
 
第三步:有对称性得出炸 有13种可能。所以地主出现炸的次数为 Na = 13*na = 13*c(50,16)*c(34,17)*c(17,17)
 
最后用p =  Na/N
 
——————————————————
以上方法正好似满足地主至少有一个炸弹,因为仅仅保证了一个。
要是仅有一个得话,可用条件概率算算。

wang feng

unread,
Feb 1, 2010, 8:42:07 AM2/1/10
to pon...@googlegroups.com
直接数值模拟成不成?
比如生成10^8次牌局,然后计数一下就成了

ZYX

unread,
Feb 1, 2010, 7:48:01 AM2/1/10
to pon...@googlegroups.com
以上各位的答案都是基于纯概率来讨论的。如果要运用于斗地主实战,还要考虑,如果地主起手(未摸底牌前)一副炸弹也没有会否主动做地主的问题。如果认为愿意做地主暗示起手牌不错的话,则运用于实战的概率应该予以上调。

2010/2/1 bookcpp <boo...@gmail.com>:

石奇偲

unread,
Mar 9, 2011, 1:05:41 AM3/9/11
to pon...@googlegroups.com
这个才是比较简单又自然地解法吧,先算没有非王炸的概率,然后用1减.
非王炸的概率可以不用生成函数法,直接用排列组合就行了.不过手工算计算量有点大.
Reply all
Reply to author
Forward
0 new messages