1. 程式人生 > >華為2018實習生筆試程式設計題 三

華為2018實習生筆試程式設計題 三

題目描述:

有N個骰子,同時投擲出去,向上面的數字之和為A。那麼輸入為N個骰子,請計算出A,和A出現的概率。概率值,小數點保留5位。

樣例輸入:

1

樣例輸出:

[[1,0.166667], [2,0.166667], [3,0.166667], [4,0.166667], [5,0.166667], [6,0.166667]]

基本思想:

動態規劃,n個骰子點數和為s的種類數只與n-1個骰子的和有關。因為一個骰子有六個點數,那麼第n個骰子可能出現1到6的點數。所以當第n個骰子點數為1的話,f(n,s)=f(n-1,s-1),當第n個骰子點數為2的話,f(n,s)=f(n-1,s-2),…,依次類推。在n-1個骰子的基礎上,再增加一個骰子出現點數和為s的結果只有這6種情況!

那麼有:
f(n,s)=f(n-1,s-1)+f(n-1,s-2)+f(n-1,s-3)+f(n-1,s-4)+f(n-1,s-5)+f(n-1,s-6) ,0< n<=6n 

f(n,s)=0, s< n or s>6n

程式碼實現:

import java.util.Scanner;
public class Touzi {
	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		int n;
		Scanner sc = new Scanner(System.in);
		n=sc.nextInt();
		double total = Math.pow(6,n);//n個骰子一共有6的n次方個取值
		System.out.print("[["+n+","+String.format("%.6f", getSum(n,n)/total)+"], ");//控制輸出格式
		for(int i = n+1;i<6*n;i++){
			System.out.print("["+i+","+String.format("%.6f", getSum(n,i)/total)+"], ");
		}
		System.out.print("["+6*n+","+String.format("%.6f", getSum(n,6*n)/total)+"]]");
	}	
	public static int getSum(int n ,int sum){
		if(n<1||sum<n||sum>6*n){
			return 0;			
		}
		if(n==1){
			return 1;
		}
		return getSum(n-1,sum-1)+getSum(n-1,sum-2)+getSum(n-1,sum-3)+getSum(n-1,sum-4)+getSum(n-1,sum-5)+getSum(n-1,sum-6);		
	}
}

非遞迴方式實現:

已知n個骰子點數和為s的種類數只與n-1個骰子的和有關,因此可以使用兩個陣列如a[]、b[],分別儲存n-1個骰子和n個骰子點數和為s的種類數,則b[s]=a[s-1]+a[s-2]+a[s-3]+a[s-4]+a[s-5]+a[s-6]。

public class Touzi {
	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		int n;
		Scanner sc = new Scanner(System.in);
		n=sc.nextInt();
		printProbability(n);
	}	
	public static void printProbability(int n) {    
		if (n < 1)    
	       return;       
	    int[][] getSum = new int[2][];    
	    getSum[0] = new int[6 * n + 1];    
	    getSum[1] = new int[6 * n + 1];    
	    int flag = 0;    
	    for (int i = 1; i <= 6; i++)    
	    	getSum[0][i] = 1;    //n==1時
	    for (int k = 2; k <= n; ++k) {  //骰子數從2到n依次累增
	    	for (int i = 0; i < k; ++i) //當有k個骰子時,點數和小於k的情況為0 
	    		getSum[1 - flag][i] = 0;    
	    	for (int sum = k; sum <= 6 * k; ++sum) { //k個骰子時,sum最小為k,最大為6*k   
	    		getSum[1 - flag][sum] = 0;    
	    		for (int j = 1; j <= sum && j <= 6; ++j)//b[s]=a[s-1]+a[s-2]+a[s-3]+a[s-4]+a[s-5]+a[s-6]      
	    			getSum[1 - flag][sum] += getSum[flag][sum - j];  
	    		}    
	    	flag = 1 - flag;    
	    	}    
	    double total = Math.pow(6,n);//n個骰子一共有6的n次方個取值   
	    for (int i = n; i <= 6 * n; i++) {       
	    	System.out.println(String.format("["+i+","+"%.6f", getSum[flag][i] / total)+"] ");    
	    }    
	}    
}