Coins(概率dp)
Coins I
题目描述
Alice and Bob are playing a simple game. They line up a row of n identical coins, all with the heads facing down onto the table and the tails upward.
For exactly m times they select any k of the coins and toss them into the air, replacing each of them either heads-up or heads-down with the same possibility. Their purpose is to gain as many coins heads-up as they can.
输入
The input has several test cases and the first line contains the integer t (1 ≤ t ≤ 1000) which is the total number of cases.
For each case, a line contains three space-separated integers n, m (1 ≤ n, m ≤ 100) and k (1 ≤ k ≤ n).
输出
For each test case, output the expected number of coins heads-up which you could have at the end under the optimal strategy, as a real number with the precision of 3 digits.
样例输入
6
2 1 1
2 3 1
5 4 3
6 2 3
6 100 1
6 100 2
样例输出
0.500
1.250
3.479
3.000
5.500
5.000
题目思路
每次选k个中t个为正面的概率为c(k,t)*0.5^k,所以需要预处理一下100以内的组合数,否则会超时。
以操作次数作为阶段,有几个硬币为正面作为状态,dp[i][j]表示i次操作后正面个数为j的概率。
这里注意,如果j<=n-k,因为取最优策略,所以不会有正面硬币被选来抛。
反之有可能有正面硬币被抛为反面,所以当j超过n-k时,不管j超过多少,硬币为正面的个数都为n-k加上本次抛的为正面的个数,因为原来为正面的也需要重新抛。
所以状态的转移如下
if(j<=n-k)
dp[i][j+t]+= dp[i-1][j]*p*c[k][t];
else
dp[i][n-k+t]+= dp[i-1][j]*p*c[k][t];
最后的答案为n次操作后硬币正面的个数乘以它的概率相加。
代码如下
#include<bits/stdc++.h> #define ll long long #define mod 1000000007 using namespace std; int t,n,m,k; double dp[110][110],p,c[101][101]; int main() { for (int i=0;i<=100;i++) for (int j=0;j<=i;j++) if (j==0||i==j) c[i][j]=1; else c[i][j]=c[i-1][j-1]+c[i-1][j]; cin>>t; while(t--) { scanf("%d%d%d",&n,&m,&k); memset(dp,0,sizeof(dp)); dp[0][0] = 1; p = pow(0.5,k); for(int i = 1;i<=m;i++)//阶段 for(int j = 0;j<=n;j++)//状态 for(int t = 0;t<=k;t++) if(j<=n-k) dp[i][j+t]+= dp[i-1][j]*p*c[k][t]; else dp[i][n-k+t]+= dp[i-1][j]*p*c[k][t]; double ans = 0; for(int i = 1;i<=n;i++) ans+=dp[m][i]*i; printf("%.3lf\n",ans); } return 0; }