1. 程式人生 > >ACM-ICPC 2017 Asia Urumqi:A. Coins(DP) 組合數學

ACM-ICPC 2017 Asia Urumqi:A. Coins(DP) 組合數學

pri text -m 16px thml fir several while stack

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(1t1000) 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(1n,m100)and k (1 \le k \le n)k(1kn).

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

題目來源

ACM-ICPC 2017 Asia Urumqi

題意:有n枚朝下的硬幣,我們可以投擲這些硬幣m次,每次投擲 t 枚硬幣,問最後朝上硬幣的期望

分析:最優的策略一定是:當有至少 k 枚硬幣面朝下時,則選 k 枚面朝下的硬幣去拋擲(任意k 枚都可以);如果不足 k 枚面朝下,則在選擇所有面朝下的硬幣的基礎上再額外選擇若幹面朝上的硬幣。

於是有動態規劃,記 dp[i][j]表示拋擲了 i 次後,有 j 枚硬幣面朝上的概率。他們應該滿足dp[i][0]+dp[i][1]+...+dp[i][n]=1。轉移時,考慮從當前狀態(i,j)出發,拋擲的 k 枚硬幣的所有可能結果:分別有 0~k 枚面朝上。其中 k 枚硬幣拋擲後有 l 枚面朝上的概率為 C(k,l)/2k。時間復雜度 O(nmk)。

參考博客:https://blog.csdn.net/mitsuha_/article/details/79307065

AC代碼:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define ls (r<<1)
#define rs (r<<1|1)
#define debug(a) cout << #a << " " << a << endl
using namespace std;
typedef long long ll;
const ll maxn = 205;
const ll mod = 1e9 + 7;
double dp[maxn][maxn], p[maxn], c[maxn][maxn];
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    c[0][0] = 1;
    for( ll i = 1; i <= 100; i ++ ) {
        c[i][0] = 1;
        for( ll j = 1; j <= i; j ++ ) {
            c[i][j] = c[i-1][j-1] + c[i-1][j];  //打表前一百個的組合數
        }
    }
    p[0] = 1;
    for( ll i = 1; i <= 100; i ++ ) {
        p[i] = p[i-1]/2;   //幾枚硬幣朝上的概率
    }
    ll T;
    cin >> T;
    while( T -- ) {
        ll n, m, t;
        cin >> n >> m >> t;
        memset( dp, 0, sizeof(dp) );
        dp[0][0] = 1;   //記錄投擲i次有j枚硬幣朝上的概率
        for( ll i = 0; i < m; i ++ ) {
            for( ll j = 0; j <= n; j ++ ) {
                if( dp[i][j] == 0 ) {
                    continue;
                }
                for( ll k = 0; k <= t; k ++ ) {
                    if( n-j >= t ) {   //還有硬幣沒有朝上的情況
                        dp[i+1][j+k] += dp[i][j]*c[t][k]*p[t];
                    } else {   //已經有n枚硬幣朝上了還得投擲的情況,這時會使n枚變少或者不變
                        dp[i+1][n-t+k] += dp[i][j]*c[t][k]*p[t];  //n-t代表會改變t枚硬幣的情況,k代表改變的情況朝上的情況
                    }
                }
            }
        }
        double ans = 0;
        for( ll i = 1; i <= n; i ++ ) {
            ans += dp[m][i]*i;       //計算期望
        }
        printf("%.3lf\n",ans);
    }
    return 0;
}

  

ACM-ICPC 2017 Asia Urumqi:A. Coins(DP) 組合數學