1. 程式人生 > 實用技巧 >收集郵票(概率dp)

收集郵票(概率dp)

題目大意

有n種不同的郵票,皮皮想收集所有種類的郵票。唯一的收集方法是到同學凡凡那裡購買,每次只能買一張,並且買到的郵票究竟是n種郵票中的哪一種是等概率的,概率均為1/n。但是由於凡凡也很喜歡郵票,所以皮皮購買第k張郵票需要支付k元錢。 現在皮皮手中沒有郵票,皮皮想知道自己得到所有種類的郵票需要花費的錢數目的期望。

輸入格式

  • 一行,一個數字N N<=10000

輸出格式

  • 要付出多少錢. 保留二位小數

演算法分析

  • 顯然是個期望dp
  • 首先定義dp方程
    設f[i] 表示取到 i 種郵票之後,把其它所有郵票取完的期望次數
    g[i] 表示取到i 種郵票之後,把其它所有郵票取完的期望價格
  • 那麼f[i]的轉移就是 \(f[i] = \frac{i}{n}*f[i]\)
    \(+\) \(\frac{n-i}{n}\) \(* f[i+1] + 1\) 因為已經選了i種物品 對於選下一種物品 有\(\frac{i}{n}\)的概率選到已經已經選過的物品 有\(\frac{n-i}{n}\)的概率選到未選到的物品 移項可得 \(f[i] = f[i+1]\) + \(\frac{n}{n-i}\) 這樣我們就得到了關於i 與 i + 1 的線性推關係
  • g[i] 的轉移就是 $g[i] = \(\frac{i}{n} * (g[i] + f[i] + 1)\) + \(\frac{n-i}{n}\) * (g[i+1] + f[i+1] + 1) 然後移項可得 g[i] = \(\frac{i}{n-i}\)
    + \(g[i+1] + f[i+1]\) + \(\frac{n}{n-1}\)
  • 這樣我們就可以遞推求解了

Code



#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n;
double f[maxn],g[maxn];

int main(){
    scanf("%d",&n);
    for(int i=n-1;i >= 0;--i) {
        f[i]=f[i+1]+(1.0*n)/(1.0*(n-i));
        g[i]=(1.0*i)/(1.0*(n-i))*(f[i]+1)+g[i+1]+f[i+1]+1;
    }
    printf("%.2lf\n",g[0]);
    return 0;
}