1. 程式人生 > >藍橋杯 演算法提高 ADV-123 概率計算 動態規劃

藍橋杯 演算法提高 ADV-123 概率計算 動態規劃

演算法提高 概率計算
時間限制:1.0s 記憶體限制:256.0MB
問題描述
  生成n個∈[a,b]的隨機整數,輸出它們的和為x的概率。
輸入格式
  一行輸入四個整數依次為n,a,b,x,用空格分隔。
輸出格式
  輸出一行包含一個小數位和為x的概率,小數點後保留四位小數
樣例輸入
2 1 3 4
樣例輸出
0.3333
資料規模和約定
  對於50%的資料,n≤5.
  對於100%的資料,n≤100,b≤100.

分析:由題有每個數的範圍a到b,所以每個數的概率為 1

b a + 1 \frac{1}{b-a+1}
 
思路:
  利用動態規劃,dp[i][j]表示i個數和為j的概率。
  那麼dp[i][j]就可以想成是i-1個數和為j-k時,再加k的情況。
  從a到b每個數遍歷,即a<=k<=b,dp[i][j]就是所有滿足j-k>0的情況概率之和,因為只有j-k>0時,才能得到和為j的情況,每種情況的概率相加,就是最終dp[i][j]的概率
  所以狀態轉換方程為:
d
p [ i ] [ k ]    +
=    d p [ i 1 ] [ k j ] × 1 b a + 1 ; dp[i][k]\ \ +=\ \ dp[i-1][k-j] \times \frac{1}{b-a+1};

  程式碼如下:

#include<cstring>
#include<iostream>
using namespace std;

double dp[101][10000];		//dp[i][j]表示i個數的和為j的時候的概率 

int main()
{
	int n, a, b, x;
	
	cin >> n >> a >> b >> x;
	
	//初始化
	for(int i = a; i <= b; i++)
		dp[1][i] = 1.0 / (b - a + 1); 
		
	// i個數 
	for(int i = 2; i <= n; i++)
	{
		//第i個數為j的時候
		for(int j = a; j <= b; j++)
		{
			//和為k的時候
			for(int k = j + 1; k <= x; k++)
			{
				dp[i][k] += dp[i-1][k-j] / (b - a + 1);
			}
		}
	}
	printf("%.4lf\n", dp[n][x]);
	return 0;
}