ACM-ICPC 2017 Asia Urumqi A. Coins 概率dp
Alice and Bob are playing a simple game. They line up a row of nn identical coins, all with the heads facing down onto the table and the tails upward.
For exactly mm times they select any kk 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.
Input
The input has several test cases and the first line contains the integer t (1 \le t \le 1000)t(1≤t≤1000) which is the total number of cases.
For each case, a line contains three space-separated integers nn, m (1 \le n, m \le 100)m(1≤n,m≤100) and k (1 \le k \le n)k(1≤k≤n).
Output
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 33 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
題意:有n枚最初反面朝上的硬幣,m次操作,每次選k個硬幣重新拋擲,為了使硬幣朝上的個數儘可能的多,問在最佳策略的情況下,硬幣個數的期望。
dp[i][j]表示第i次操作後有j枚硬幣朝上的概率,顯然最優策略是挑選反面朝向的硬幣重新拋擲,那麼就會有兩種情況
1:剩餘反面朝上的硬幣不少於k個,那麼很簡單,直接選k個反面朝上的硬幣
2:剩餘反面朝上的硬幣少於k個,那麼只能選所有反面朝上的硬幣,剩餘的用正面朝上的來補。
複雜度O(nmk)暴力所有情況。
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxm = 105;
double dp[maxm][maxm], p[maxm], C[maxm][maxm];
void init()
{
C[0][0] = 1;
for (int i = 1;i <= 100;i++)
{
C[i][0] = 1;
for (int j = 1;j <= i;j++)
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
}
int main()
{
int n, i, j, k, sum, t, m, r;
p[0] = 1;init();
for (i = 1;i <= 100;i++)
p[i] = p[i - 1] / 2;
scanf("%d", &t);
while (t--)
{
scanf("%d%d%d", &n, &m, &k);
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for (i = 1;i <= m;i++)
{
for (j = 0;j <= n;j++)
{
for (r = 0;r <= k;r++)
{
if (n - j >= k)
dp[i][j + r] += dp[i - 1][j] * C[k][r] * p[k];
else dp[i][n - k + r] += dp[i - 1][j] * C[k][r] * p[k];
}
}
}
double ans = 0;
for (i = 1;i <= n;i++)
ans += dp[m][i] * i;
printf("%.3f\n", ans);
}
return 0;
}