`
vv_1024
  • 浏览: 111664 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

计算N个骰子掷出的和的概率问题 —— 用金字塔模型求解

    博客分类:
  • J2SE
阅读更多

之前 javaeye 网站上有人写过 3颗骰子能掷出多少种结果 的一道面试题,用了面向对象的思考方式,后来某天深夜自己想了又想,发现可以把这个问题转化为数学模型,用金字塔模型,再采用逆推推出了 N个骰子掷出的和的概率算法。

 

 

1颗骰子,一共6面,每一面掷出的概率都一样,在1维空间中表示,相当于造6层金字塔的一条边

2颗骰子,在2维空间中表示。。。 (画图画了好久,直接用画图板手工绘制的,没有3d效果,大家想象成3d的吧

 

 

下面表示的是4颗骰子映射出来的4维空间模型。怎么理解呢? 就在3维空间上加一个时间吧,第一座金子公元前2000年开始建造,每年造一层,第二座金字塔公元前1999年开始建造,第三座金字塔公元前1998年开始建造,到了公园前1995年的时候,就变成下面这种状态了。

5颗骰子,依次类推,5维空间的表示,再加一个地点吧,公园前1995年的时候在埃及造了上面4维空间中的这些金字塔,一共126块砖,同年在玛雅造了5座金字塔,(假设玛雅比埃及晚造1年),其它地区的金子塔也在建造之中,都依次晚造1年。这样就形成了一个类似金子塔阶梯的5维空间。

 

 

同样,6维,7维……都和骰子投掷出来的和的概率相对应。如果把上面的每块砖都用数组来标记,就变成下面的形式:

 

 

 

再次提炼出数字规律

 

1颗:1,1,1,1,1,1
2颗:1,2,3,4,5,6
3颗:1,3,6,10,15,21
4颗:1,4,10,20,35,56
5颗:1,5,15,35,70,126

 

发现规律了吧,每组数中的数字都是上一组数字前几位数的和。

 

下面贴上java实现程序,灵感闪现,仓促下笔,算法不是很简洁,没有完全构造对象,用了数组和递归,可能阅读比较晦涩。

 

package org.vv.algorithm.number;

import java.util.Map;
import java.util.TreeMap;
/**
 * 计算 骰子的组合 概率 问题
 * @author 俞立全
 * @version 2009-10-20
 */
public class A {
	
	/**
	 * 初始化定义骰子的个数
	 */
	private static int[] n = {1,1,1,1,1,1};
	
	//排列,组合
	/*
	 * 骰子的组合就是求和的概率,如2颗骰子 出现和为2的概率是1,3的概率是2,4的概率是3,5的概率是4,6的概率是5,7的概率是6 ,概率的总和也就是骰子的组合。
	 */
	//1,1,1,1,1,1  
	//6,5,4,3,2,1 	
	//21,15,10,6,3,1	
	//56,35,20,10,4,1
	//126,70,35,15,5,1
	//上面每一个结果都是
	
	/**
	 * 计算骰子组合的总数(排列)
	 * @param n 骰子面数
	 * @param num 骰子数量
	 * @return
	 */
	public static int[] exec(int[] n,int num){
		if(num>1){
			num--;
			System.out.println("递归:"+num);
			for(int i=0;i<n.length;i++){
				for(int j=0;j<n.length-i-1;j++){
					//每次减少一位
					n[i] += n[j+i+1];
				}
			}
			exec(n,num);
		}
		return n;
	}
	
	
	/////////////////////////////////////////////////////////
	
	
	/**
	 * 初始化骰子
	 * @param num1 骰子面数 一般为6面
	 * @param num2 骰子个数
	 */
	public static int[] get(int num){
		int[] n = new int[num];
		for (int i = 0; i < n.length; i++) {
			n[i]=1;
		}
		return n;
	}
	
	
	/**
	 * 显示输出的行号
	 */
	private static int numbers=1;
	/**
	 * 开始枚举数组时开始的位置,从n[0]递增,由于使用递归,只能定义为成员变量。
	 */
	private static int i=0;
	/**
	 * n[0]位置是否满足条件 n[i]>=num  由于使用递归,只能定义为成员变量。
	 */
	private static boolean x = true;
	
	/**
	 * 枚举出所有数组
	 * @param n 初始的数组,如{1,1,1,1}
	 * @param num 骰子的面数,一般为6
	 * @param x 
	 */
	public static void verify(int[] n,int num){
		if(x && (include(n) || isCalculateCount)){
			printArray(n);
			numbers++;
			//是否统计骰子掷出的概论
			if(isCalculateCount){
				getCount(n);
			}
		}
		if(!isEnd(n,num)){
			if(n[i]>=num){
				x=false;
				n[i]=1;
				i=i+1;
			}else{
				x=true;
				n[i]++;
				i=0;
			}
			verify(n,num);
		}
	}
	
	/**
	 * 判断是否结束 ,即 6,6,6,6 形式
	 * @param n
	 * @param num
	 * @return
	 */
	public static boolean isEnd(int[] n,int num){
		boolean rt = true;
		for(int i=0;i<n.length;i++){
			if(n[i]==6){
				rt &= true;	//只有都为true才返回true
			}else{
				rt &= false;
			}
		}
		return rt;
	}
	
	/**
	 * 判断数组中相邻两位左边的值是否大于等于右边的值,大于等于有效,返回true,只要有一个组小于就返回false;
	 * @param n
	 * @return
	 */
	public static boolean include(int[] n){
		boolean rt = true;
		for(int i=0;i<n.length-1;i++){
			if(n[i] >= n[i+1]){
				rt &= true;
			}else{
				rt &= false;
			}
		}
		return rt;
	}
	
	/**
	 * 打印数组中的元素到控制台
	 * @param source
	 */
	public static void printArray(int[] data) {
		System.out.print(numbers+" : ");
		for (int i : data) {
			System.out.print(i + " ");
		}
		System.out.println();
	}
	
	
	/////////////////////////////////// 概论判断,使用概论判断就必须使用排列,包括重复的组合。
	private static boolean isCalculateCount = true;
	
	private static Map<Integer,Integer> map = new TreeMap<Integer,Integer>();
	
	public static void getCount(int[] n){
		Integer count = 0;
		Integer number = 0;
		for(int i=0;i<n.length;i++){
			count +=n[i];
		}
		//判断比较
		if(map.get(count)!=null)
		{
			number = map.get(count)+1;
			map.remove(count);
			map.put(count,number);
		}else{
			map.put(count, 1);
		}
	}
	
	/**
	 * 执行计算
	 * @param args
	 */
	public static void main(String[] args) {
		//定义骰子的数量
		int count = 2;
		//计算骰子组合的总数(无序)
		int[] x = A.exec(n, count);
		int sum = 0;
		for(int i=0;i<x.length;i++){
			System.out.println(x[i]);
			sum+=x[i];
		}
		System.out.println("最后的总和:"+sum);
		
		//遍历骰子(排列或组合由 isCalculateCount 属性控制)
		A.isCalculateCount = false;
		A.verify(A.get(count),6);

		//概论统计
		for(java.util.Map.Entry<Integer,Integer> entry : map.entrySet()){
			Integer key = entry.getKey();
			Integer value = entry.getValue();
			System.out.println("骰子掷出的和: " + key + "  出现次数:" + value);
		}
	}
}

 

 

从中也总结出一条经验,就是循环的处理,并且在很多需求中屡试不爽。如果明确循环次数就用 for while 等,如果不明确循环次数,并且返回或处理对象结构相同就可以用递归,比如生成树形结构的目录。

 

 

最后运行代码的结果:(3颗骰子)

 

递归:2
递归:1
21
15
10
6
3
1
最后的总和:56
1 : 1 1 1
2 : 2 1 1
3 : 3 1 1
4 : 4 1 1
5 : 5 1 1
6 : 6 1 1
7 : 2 2 1
8 : 3 2 1
9 : 4 2 1
10 : 5 2 1
11 : 6 2 1
12 : 3 3 1
13 : 4 3 1
14 : 5 3 1
15 : 6 3 1
16 : 4 4 1
17 : 5 4 1
18 : 6 4 1
19 : 5 5 1
20 : 6 5 1
21 : 6 6 1
22 : 2 2 2
23 : 3 2 2
24 : 4 2 2
25 : 5 2 2
26 : 6 2 2
27 : 3 3 2
28 : 4 3 2
29 : 5 3 2
30 : 6 3 2
31 : 4 4 2
32 : 5 4 2
33 : 6 4 2
34 : 5 5 2
35 : 6 5 2
36 : 6 6 2
37 : 3 3 3
38 : 4 3 3
39 : 5 3 3
40 : 6 3 3
41 : 4 4 3
42 : 5 4 3
43 : 6 4 3
44 : 5 5 3
45 : 6 5 3
46 : 6 6 3
47 : 4 4 4
48 : 5 4 4
49 : 6 4 4
50 : 5 5 4
51 : 6 5 4
52 : 6 6 4
53 : 5 5 5
54 : 6 5 5
55 : 6 6 5
56 : 6 6 6

 

 

打开概率计算后的计算结果,(计算概率,就包括了重复,如 112 211 121 都要计算在内)

递归:2
递归:1
21
15
10
6
3
1
最后的总和:56


1 : 1 1 1
2 : 2 1 1
3 : 3 1 1
4 : 4 1 1
5 : 5 1 1
6 : 6 1 1
7 : 1 2 1
8 : 2 2 1
9 : 3 2 1
10 : 4 2 1
11 : 5 2 1
12 : 6 2 1
13 : 1 3 1
14 : 2 3 1
15 : 3 3 1
16 : 4 3 1
17 : 5 3 1
18 : 6 3 1
19 : 1 4 1
20 : 2 4 1
21 : 3 4 1
22 : 4 4 1
23 : 5 4 1
24 : 6 4 1
25 : 1 5 1
26 : 2 5 1
27 : 3 5 1
28 : 4 5 1
29 : 5 5 1
30 : 6 5 1
31 : 1 6 1
32 : 2 6 1
33 : 3 6 1
34 : 4 6 1
35 : 5 6 1
36 : 6 6 1
37 : 1 1 2
38 : 2 1 2
39 : 3 1 2
40 : 4 1 2
41 : 5 1 2
42 : 6 1 2
43 : 1 2 2
44 : 2 2 2
45 : 3 2 2
46 : 4 2 2
47 : 5 2 2
48 : 6 2 2
49 : 1 3 2
50 : 2 3 2
51 : 3 3 2
52 : 4 3 2
53 : 5 3 2
54 : 6 3 2
55 : 1 4 2
56 : 2 4 2
57 : 3 4 2
58 : 4 4 2
59 : 5 4 2
60 : 6 4 2
61 : 1 5 2
62 : 2 5 2
63 : 3 5 2
64 : 4 5 2
65 : 5 5 2
66 : 6 5 2
67 : 1 6 2
68 : 2 6 2
69 : 3 6 2
70 : 4 6 2
71 : 5 6 2
72 : 6 6 2
73 : 1 1 3
74 : 2 1 3
75 : 3 1 3
76 : 4 1 3
77 : 5 1 3
78 : 6 1 3
79 : 1 2 3
80 : 2 2 3
81 : 3 2 3
82 : 4 2 3
83 : 5 2 3
84 : 6 2 3
85 : 1 3 3
86 : 2 3 3
87 : 3 3 3
88 : 4 3 3
89 : 5 3 3
90 : 6 3 3
91 : 1 4 3
92 : 2 4 3
93 : 3 4 3
94 : 4 4 3
95 : 5 4 3
96 : 6 4 3
97 : 1 5 3
98 : 2 5 3
99 : 3 5 3
100 : 4 5 3
101 : 5 5 3
102 : 6 5 3
103 : 1 6 3
104 : 2 6 3
105 : 3 6 3
106 : 4 6 3
107 : 5 6 3
108 : 6 6 3
109 : 1 1 4
110 : 2 1 4
111 : 3 1 4
112 : 4 1 4
113 : 5 1 4
114 : 6 1 4
115 : 1 2 4
116 : 2 2 4
117 : 3 2 4
118 : 4 2 4
119 : 5 2 4
120 : 6 2 4
121 : 1 3 4
122 : 2 3 4
123 : 3 3 4
124 : 4 3 4
125 : 5 3 4
126 : 6 3 4
127 : 1 4 4
128 : 2 4 4
129 : 3 4 4
130 : 4 4 4
131 : 5 4 4
132 : 6 4 4
133 : 1 5 4
134 : 2 5 4
135 : 3 5 4
136 : 4 5 4
137 : 5 5 4
138 : 6 5 4
139 : 1 6 4
140 : 2 6 4
141 : 3 6 4
142 : 4 6 4
143 : 5 6 4
144 : 6 6 4
145 : 1 1 5
146 : 2 1 5
147 : 3 1 5
148 : 4 1 5
149 : 5 1 5
150 : 6 1 5
151 : 1 2 5
152 : 2 2 5
153 : 3 2 5
154 : 4 2 5
155 : 5 2 5
156 : 6 2 5
157 : 1 3 5
158 : 2 3 5
159 : 3 3 5
160 : 4 3 5
161 : 5 3 5
162 : 6 3 5
163 : 1 4 5
164 : 2 4 5
165 : 3 4 5
166 : 4 4 5
167 : 5 4 5
168 : 6 4 5
169 : 1 5 5
170 : 2 5 5
171 : 3 5 5
172 : 4 5 5
173 : 5 5 5
174 : 6 5 5
175 : 1 6 5
176 : 2 6 5
177 : 3 6 5
178 : 4 6 5
179 : 5 6 5
180 : 6 6 5
181 : 1 1 6
182 : 2 1 6
183 : 3 1 6
184 : 4 1 6
185 : 5 1 6
186 : 6 1 6
187 : 1 2 6
188 : 2 2 6
189 : 3 2 6
190 : 4 2 6
191 : 5 2 6
192 : 6 2 6
193 : 1 3 6
194 : 2 3 6
195 : 3 3 6
196 : 4 3 6
197 : 5 3 6
198 : 6 3 6
199 : 1 4 6
200 : 2 4 6
201 : 3 4 6
202 : 4 4 6
203 : 5 4 6
204 : 6 4 6
205 : 1 5 6
206 : 2 5 6
207 : 3 5 6
208 : 4 5 6
209 : 5 5 6
210 : 6 5 6
211 : 1 6 6
212 : 2 6 6
213 : 3 6 6
214 : 4 6 6
215 : 5 6 6
216 : 6 6 6
骰子掷出的和: 3  出现次数:1
骰子掷出的和: 4  出现次数:3
骰子掷出的和: 5  出现次数:6
骰子掷出的和: 6  出现次数:10
骰子掷出的和: 7  出现次数:15
骰子掷出的和: 8  出现次数:21
骰子掷出的和: 9  出现次数:25
骰子掷出的和: 10  出现次数:27
骰子掷出的和: 11  出现次数:27
骰子掷出的和: 12  出现次数:25
骰子掷出的和: 13  出现次数:21
骰子掷出的和: 14  出现次数:15
骰子掷出的和: 15  出现次数:10
骰子掷出的和: 16  出现次数:6
骰子掷出的和: 17  出现次数:3
骰子掷出的和: 18  出现次数:1

 

  • 大小: 10.1 KB
  • 大小: 15.2 KB
  • 大小: 14.2 KB
  • 大小: 6.2 KB
2
1
分享到:
评论
1 楼 xxtianxiaxing 2012-08-10  
您好,实在不理解这个算法,私下请教下,给个联系方式,

相关推荐

    C#项目掷骰子——小游戏

    在本项目中,"C#项目掷骰子——小游戏"是一个使用C#编程语言开发的简单游戏应用。这个游戏的核心机制是模拟掷骰子的过程,它可能包含多个回合或轮次,每个回合玩家或计算机都会投掷一个或多个骰子,然后根据骰子的...

    Unity3D掷筛子游戏源码

    4. **动画系统**:为了使游戏更加生动,骰子掷出后应有一个翻滚动画。Unity的动画系统可以制作骰子旋转的动画,通过`Animator`组件和关键帧设置实现。也可以利用Unity的物理引擎,让骰子自然地滚动到停止位置。 5. ...

    掷骰子MATLAB实现

    想知道用MATLAB快速搞定掷骰子概率问题就下来研究吧!

    掷色子游戏 掷色子游戏 掷色子游戏

    2. **概率计算**:掷色子游戏涉及到各种概率问题,例如计算特定点数出现的概率。一个六面的标准色子,每个面出现的概率是1/6。对于两个或多个色子的组合,我们需要计算组合出现的概率,例如两个色子总点数为7的概率...

    模拟掷色子_matlab

    资源名:模拟掷色子_matlab 资源类型:matlab项目全套源码 源码说明: 全部项目源码都是经过测试校正后百分百成功运行的,如果您下载后不能运行可联系我进行指导或者更换。 适合人群:新手及有一定经验的开发人员

    可以与计算机玩掷骰子游戏

    在代码组织上,可以采用面向对象编程(OOP)的思想,定义一个`DiceGame`类,包含`Player`对象和`Computer`对象,每个对象都有自己的点数属性和掷骰子方法。这样可以使代码结构清晰,易于维护和扩展。 最后,测试和...

    部编版第3课时 实践活动——掷一掷.doc

    【实践活动——掷一掷】是部编版课程中的一个实践环节,主要目的是通过掷骰子的游戏,让学生在实际操作中理解和应用概率与统计的相关知识。这个活动涉及的主要知识点包括: 1. **组合知识**:在活动中,学生需要...

    微信小程序掷骰子掷色子.zip

    在这个“微信小程序掷骰子掷色子.zip”项目中,我们可以看到一个用于创建趣味性游戏的小程序示例,用户可以通过这个小程序体验在线掷骰子或掷色子的乐趣。 首先,我们需要理解微信小程序的基本结构。一个小程序由多...

    H5小游戏掷骰子

    2. **JavaScript**:JavaScript是驱动这个游戏的核心语言,负责处理用户的交互、随机数生成、骰子的掷出结果计算以及画面更新等功能。例如,当用户点击掷骰子按钮时,JavaScript会触发一个事件处理器,生成1到6之间...

    VB掷骰子游戏.rar

    在这个“VB掷骰子游戏”项目中,我们看到的是如何利用VB来实现一个基本的随机数生成器,模拟真实的掷骰子过程。在这个过程中,VB的随机数生成功能扮演了核心角色。 在VB中,我们可以使用`Rnd`函数来生成0到1之间的...

    Java 掷骰子游戏

    Java的掷骰子游戏,游戏规则:1、此游戏中,游戏者将滚动两个骰子。每一个骰子有六个面, 分别代表1、2、3、4、5、6。当骰子停下以后,计算两个骰子 表面的点数和。如果第一轮掷的点数和等于7或11,则游戏者胜; ...

    掷3个骰子游戏2.0.

    掷3个骰子游戏2.0.用C做的。掷3个骰子游戏2.0.用C做的。掷3个骰子游戏2.0.用C做的。掷3个骰子游戏2.0.用C做的。掷3个骰子游戏2.0.用C做的。

    完整的掷骰子游戏

    掷骰子游戏是一种常见的娱乐活动,它涉及到概率、随机性和策略。在这个“完整的掷骰子游戏”中,我们可以探讨以下几个IT相关的知识点: 1. 图片处理:描述中提到的“好看的图片”暗示了游戏可能使用了图形用户界面...

    投骰子游戏

    如果和是其他数字(4、5、6、8、9或10),就确定了一个点数,继续掷骰子,直到掷出一个7或者掷出与第一次相同的点数,如果掷出的是7,你就输了,如果掷出的点数与第一次掷出的点数相同,你就赢了。输一次或赢一次算一...

    【初中数学flssh动画素材】掷骰子

    掷骰子是初中数学中一个常见且有趣的概率教学实例,它涉及到随机事件、可能性和概率等概念。在本文中,我们将深入探讨与这个主题相关的数学知识点,并结合使用FLSH(Flash)动画作为辅助教学工具的优势。 首先,让...

    FPGA课程设计——模拟掷骰子

    基于cyclone IV的板载资源,设计利用vhdl语言设计的小游戏的课程设计——模拟掷骰子

    mengtekaluo.rar_MATLAB抛色子_matlab掷骰子_matlab编写dice_蒙特卡洛_骰子

    标签进一步明确了这个项目的主题:“matlab抛色子”、“matlab掷骰子”、“matlab编写dice”、“蒙特卡洛”和“骰子”。这些标签强调了MATLAB在实现骰子游戏模拟中的应用,以及蒙特卡洛方法在解决这个问题中的核心...

    DiceRollSimulator:掷骰子模拟器。 模拟n个骰子掷骰,直到该骰子的每个骰子的“ x面”被“掷出”为止

    然后,一个角色说出以相同的60,466,176:1投掷10个骰子的概率。 答对了。 灵感。 因此,这个多线程模拟器诞生了。 我编写的代码简单易懂,并利用了多线程功能,并且希望对其他好奇的人有用。 此代码根据MIT许可...

    用python编写一个掷骰子的小程序完整project

    标题中的“用Python编写一个掷骰子的小程序完整project”是指使用Python编程语言设计和实现一个模拟掷骰子的游戏。这个项目可能包含了用户界面、随机数生成以及结果显示等功能,是初学者学习Python GUI编程和游戏...

    掷骰子游戏设计

    - **成员函数Player::Integral(int number)**:计算玩家的积分,包括积分的变化和掷骰子的次数。 - **成员函数Player::Initial()**:创建玩家链表,将所有玩家链接起来形成一个环。 - **成员函数Player::Game()**:...

Global site tag (gtag.js) - Google Analytics