`
vv_1024
  • 浏览: 110094 次
  • 性别: 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  
您好,实在不理解这个算法,私下请教下,给个联系方式,

相关推荐

    模拟掷色子_matlab

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

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

    微信小程序掷骰子掷色子

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

    我们学校的资源;是个c#语言写的;可以说是个小游戏吧!里面有几个经典的循环哦!需要的朋友可以下载哦!

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

    掷色子 游戏 有简单的游戏分析,可为复杂游戏提供代码掷色子游戏 掷色子游戏 掷色子游戏 掷色子游戏

    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做的。

    投骰子游戏

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

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

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

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

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

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

    该程序可以与计算机玩掷骰子,该游戏简约而不简单~~

    python模拟掷骰子

    下面的类模拟掷一个骰子:使用这个类来创建图表前,先来掷 D6 骰子,将结果打印出来,并检查结果是否合理:为分析掷一个 D6 骰子的结果,我们计算每个点数出现的次数有了频率列表后,我们就可以绘制一个表示结果的...

    掷骰子MATLAB实现

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

    python实现简易掷色子

    python实现简易掷色子,这个"骰子掷色子"应用程序提供了一个简单的图形用户界面,让用户来模拟掷色子的过程。用户可以在输入框中输入骰子的面数,并点击按钮来掷色子。程序会根据用户输入的面数创建一个骰子对象,...

    一个掷骰子游戏

    专为iPhone开发者准备的一个掷骰子游戏 开源,简单

    掷骰子游戏设计

    掷骰子游戏设计掷骰子游戏设计掷骰子游戏设计掷骰子游戏设计掷骰子游戏设计掷骰子游戏设计

    C 掷双骰子算法示例.rar

    C 掷双骰子的相关算法演示代码,“掷双骰”游戏家喻户晓,其游戏规则如下:每次掷两个骰子,每个骰子的6面上分别标有1、2、3、4、5、6,两个骰子停止滚动后,计算其向上的点数之和。本代码将还原游戏场景。  假如...

    LABVIEW习题 掷骰子

    一个考试题,创建VI模仿掷骰子(可能的值为1~6),记录每个值出现的次数。输入掷骰子的次数,输出每个值。

    VB掷骰子游戏.rar

    VB掷骰子游戏,练习VB随机数的,每次掷的骰子,得到的结果都不一样,模拟出了掷骰子场景。

    掷骰子概率统计C++源程序

    产生掷骰子的随机数,输入掷骰子的次数,也已得到掷得的点数统计图。

    Python Tkinter实例——模拟掷骰子

    什么是Tkinter? Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。 由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、适合初学者入门...

Global site tag (gtag.js) - Google Analytics