这个题目来自剑指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