百度百科:
排列,就是指从给定个数的元素中取出指定个数的元素进行排序。
组合,则是指从给定个数的元素中仅仅取出指定个数的元素,不考虑排序。
排列组合的中心问题是研究给定要求的排列和组合可能出现的情况总数。
问题:根据摇色子猜点数。求出所有色子组合的概率。
Input
一个正整数n,表示有多少个骰子,n不超过11。
Output
每行一个double类型的数据,表示组合为1、2、3…点数的概率,结果保留十位小数。
- 用参考文章的第一个问题的方法,用到的时间为950ms,超时差不多5倍。
认真观察结果间的关系,明显具有对称关系,用参考文章的方法并不适用
虽然参考文章的问题和色子这题确实本质上一致,但色子一题有明显的特性,所以应该换个思路想,不是列出全排列的所有取值可能,然后算它的概率,而是列出符合我要求的值的所有取值可能,然后算它的概率
不是这样
而是,当色子数为3时,我想要求出总值为3~3+Math.ceil((arr.length-1)/2)的概率,即总值为3 ~ 10的概率。arr是存放所有取值的数组。剩下的11 ~18的概率可以复制3 ~10的。
找出的排列应该是上面这样的
这时候问题变成了整数划分问题。但是这个整数划分对划分的参数个数有限制,比如,要求总值为4的全排列,但是要求参数只能为3个,因为色子只有3个。感觉整数划分也挺难的,因为整数划分一般都是计算有几种划分方式。被自己给整无语了。
再看看参考文章的排列结果,再一个循环内总值一定是慢慢往上升的,只要限制住总值,掐灭苗头,好像就可以了。依旧超时5倍。
算了,把代码放下,再见。
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Stack;
import java.util.stream.Collectors;
public class Dice {
public static Stack<Integer> stack = new Stack<Integer>();
//public static List<Integer> list=new ArrayList<Integer>();
//map存放值和对应概率
public static Map<Integer,Double>map=new HashMap<Integer,Double>();
public static int n=0;
public static double temp=0;
public static int sumTemp=0;
public static int maxSum=0;
public static void main(String[]args ){
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
double p=Math.pow(1/6d,n);
// System.out.println("p="+p);
int shu[] = {1,2,3,4,5,6};
//这里先把值全输入
for(int i=n;i<=6*n;i++){
map.put( i, 0.0 );
}
sumTemp=n+(int)Math.ceil((map.size()-1)/2);
// System.out.println("sumTemp"+sumTemp);
f(shu,n,0);
maxSum=6*n+n;
// System.out.println("maxsum"+maxSum);
for(int i=n;i<=sumTemp;i++){
if(map.containsKey(i)){
temp=map.get(i);
map.put(maxSum-i, temp);
// System.out.println("n="+i+"maxSum-n="+(maxSum-i)+"temp="+temp);
}
}
// BigDecimal bd1=new BigDecimal(map.get(3));
// BigDecimal bd2=new BigDecimal(Math.pow(1/6,3));
// BigDecimal rs=bd1.multiply(bd2);
// System.out.println("BigDecimal="+bd2);
Double d=0.0;
for(int i=n;i<=6*n;i++){
// System.out.println("map.get(i)="+map.get(i));
d=map.get(i)*p;
System.out.println(String.format("%.10f", d));
// map.put(n, d);
}
// for(Map.Entry<Integer, Double> entry:map.entrySet()){
// System.out.println("key="+entry.getKey()+"\tvalue="+entry.getValue());
// }
}
/**
* 这个用来计算每个值出现的组合次数
* @param shu 每个参数取值的范围
* @param targ 总共取几个参数
* @param cur 当前正在的第几个参数的下标
*/
private static void f(int[] shu, int targ, int cur) {
// TODO Auto-generated method stub
if(cur == targ) {
// System.out.println(stack);
int sum=0;
for(int i=0;i<n;i++){
sum+=stack.elementAt(i);
if(sum>sumTemp){
return;
}
}
if(map.containsKey(sum)){
// System.out.println("sum="+sum);
temp=map.get(sum);
map.put(sum, temp+1);
}
return;
}
for(int i=0;i<shu.length;i++) {
stack.add(shu[i]);
f(shu, targ, cur+1);
stack.pop();
}
}
}
参考文章:zzl的日常work