n个色子的和的概率

这个题目来自剑指offerhttp://zhedahht.blog.163.com/blog/static/254111742009101524946359/

n个骰子的点数和的最小值为n,最大值为6n。因此,一个直观的思路就是定义一个长度为6n-n的数组,和为S的点数出现的次数保存到数组第S-n个元素里。另外,我们还知道n个骰子的所有点数的排列数6^n。一旦我们统计出每一点数出现的次数之后,因此只要把每一点数出现的次数除以n^6,就得到了对应的概率。

之前编写过全排列的程序,

/* Note:Your choice is C IDE */
#include "stdio.h"
#include<malloc.h>
#include<math.h>

int sum_arr_n(int arr[],int n)
{
	int i;
	int sum=0;
	for(i=0;i<n;i++)
		sum+=arr[i];
	return sum;
	
}
void QuanPaiLei(int n,int m){//这里N为6,m为色子数
	int count=0;	
	int arr[100];	
	int i,j=0;
	int total=pow(n,m);
	int *arr_sum=(int *)malloc((n*m+1)*sizeof(int));
	if(NULL==arr_sum)	
		return;
	memset(arr_sum,0,(n*m+1)*sizeof(int));
	i=0;
	arr[0]=1;	
	while(1){		
		if(i==m-1){
			arr_sum[sum_arr_n(arr,m)]++;
			count++;
		}
		if(i<m-1){
			i++;
			arr[i]=1;每个都要从1开始
			continue;		
		}		
		while(arr[i]==n)
			i--;
		if(i>=0)
			arr[i]++;
		else
			break;
	}
	
	for(i=1;i<=n*m;i++)
	{
		if(arr_sum[i]!=0)
			printf("%d:%d/%d\n",i,arr_sum[i],total);
			//printf("%d:%.2f\n",i,arr_sum[i]*1.0/total);		
	}
	free(arr_sum);
}

void main()
{
    QuanPaiLei(6,4);//即4个色子的情况:
}
4:1/1296
5:4/1296
6:10/1296
7:20/1296
8:35/1296
9:56/1296
10:80/1296
11:104/1296
12:125/1296
13:140/1296
14:146/1296
15:140/1296
16:125/1296
17:104/1296
18:80/1296
19:56/1296
20:35/1296
21:20/1296
22:10/1296
23:4/1296
24:1/1296



             Press any key to continue

2个色子的情况

2:1/36
3:2/36
4:3/36
5:4/36
6:5/36
7:6/36
8:5/36
9:4/36
10:3/36
11:2/36
12:1/36

________________________________________________________________________________________________________

其他解法1.递归的方式

不要求输出每种排列方式。n个色子,则组合的和结果在n-6n之间,从而共有5n+1种和。假设要得到的和为sum

每个色子在1-6之间,若第i(1-n)个骰子点数为m,则之后的点和等于sum-m.若sum-m==0同时i==n,则说明是一个正确的组合方式。

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void Get_sum_count(int n,int sum,int *count)//n个骰子之和等于sum的可能组合数,count是记录组合数目
{
	int i;
    if(sum < 0) 
        return;
    if(0==n && sum!= 0)
       return;
    if(n==0 && sum==0)//找到一组可行解,count++
    {
       (*count)++;
    }
    for(i=1;i<7;i++)//以下为递归过程
    {
       Get_sum_count(n-1,sum-i,count);//如果倒数第n个骰子是点数是i,
       //那么剩下的n-i个骰子的点数之和要等于sum-i,才能得出一个有效解
       //每次递归sum减少。
    }     
}
int main()
{
   int count = 0;//n个骰子点数之和为sum的组合数目
   int n = 0,i,j;
   int sum = 0;
   int total;//=pow()
   int *arr_sum=NULL;//用于指向和的数组
   do{
   		printf("输入骰子数\n");
        scanf("%d",&n);
      
   }while(n<1); 
   arr_sum= (int*)malloc((n*5+1)*sizeof(int));//n个骰子点数和只有5*n+1种。在n,到6*n之间
   memset(arr_sum,0,(n*5+1)*sizeof(int));  
   for(i = n;i < 6*n+1;i++)//i为n个骰子的和
   {       
      Get_sum_count(n,i,&count);
      sum += count;
	  arr_sum[i-n] = count;
	  count = 0;
   }
   total=pow(6,n);
   for(j=0;j<n*5+1;j++)
   {
      printf("%d:%d/%d\n",j+n,arr_sum[j],total);
   }
   free(arr_sum); 
   return 0 ;
}

输入骰子数
 3
3:1/216
4:3/216
5:6/216
6:10/216
7:15/216
8:21/216
9:25/216
10:27/216
11:27/216
12:25/216
13:21/216
14:15/216
15:10/216
16:6/216
17:3/216
18:1/216



             Press any key to continue

转载请标明出处: http://blog.csdn.net/lin200753/article/details/27825751

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值