概率期望dp

概率期望

LOOPS

d p [ i ] [ j ] dp[i][j] dp[i][j]表示从 i , j i, j i,j r , c r, c r,c的期望,有 d p [ i ] [ j ] = p 0 × d p [ i ] [ j ] + p 1 × d p [ i ] [ j + 1 ] + p 2 × d p [ i + 1 ] [ j ] + 2 dp[i][j] = p_0 \times dp[i][j] + p_1 \times dp[i][j + 1] + p_2 \times dp[i + 1][j] + 2 dp[i][j]=p0×dp[i][j]+p1×dp[i][j+1]+p2×dp[i+1][j]+2

d p [ i ] [ j ] = ( p 1 × d p [ i ] [ j + 1 ] + p 2 × d p [ i + 1 ] [ j ] + 2 ) × 1 1 − p 0 dp[i][j] = (p_1 \times dp[i][j + 1] + p_2 \times dp[i + 1][j] + 2) \times \frac{1}{1 - p_0} dp[i][j]=(p1×dp[i][j+1]+p2×dp[i+1][j]+2)×1p01,从后面开始转移。

#include <bits/stdc++.h>

using namespace std;

const double eps = 1e-7;

const int N = 1e3 + 10;

double dp[N][N], p[N][N][3];

int n, m;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  while (scanf("%d %d", &n, &m) != EOF) {
    for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= m; j++) {
        for (int k = 0; k < 3; k++) {
          scanf("%lf", &p[i][j][k]);
        }
      }
    }
    memset(dp, 0, sizeof dp);
    for (int i = n; i >= 1; i--) {
      for (int j = m; j >= 1; j--) {
        dp[i][j] = (p[i][j][1] * dp[i][j + 1] + p[i][j][2] * dp[i + 1][j] + 2) / (1 - p[i][j][0]);
      }
    }
    printf("%.3f\n", dp[1][1]);
  }
  return 0;
}

Aeroplane chess

类似上一题,但是就是要每次碰到能跳的位置要一直跳转到不能再跳为止。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

double dp[N];

int a[N], n, m;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  while (scanf("%d %d", &n, &m) && (n + m)) {
    memset(dp, 0, sizeof dp), memset(a, 0, sizeof a);
    for (int i = 1; i <= m; i++) {
      int x, y;
      scanf("%d %d", &x, &y);
      a[x] = y;
    }
    for (int i = n - 1; i >= 0; i--) {
      for (int j = 1; j <= 6; j++) {
        int cur = i + j;
        while (a[cur]) {
          cur = a[cur];
        }
        dp[i] += (dp[cur] + 1) / 6.0;
      }
    }
    printf("%.4f\n", dp[0]);
  }
  return 0;
}

One Person Game

容 易 推 出 : E i = ∑ p k E i + k + p 0 E 0 + 1 接 下 来 用 待 定 系 数 法 E 0 为 我 们 要 求 的 , 假 设 E i = a i E 0 + b i E i = ∑ p k ( a i + k E 0 + b i + k ) + p 0 E 0 + 1 E i = ( ∑ p k a i + k + p 0 ) E 0 + ∑ p k b i + k + 1 a i = ∑ p k a i + k + p 0 , b i = ∑ p k b i + k + 1 容易推出:E_i = \sum p_k E_{i + k} + p_0 E_0 + 1\\ 接下来用待定系数法\\ E_0为我们要求的,假设E_i = a_i E_0 + b_i\\ E_i = \sum p_k (a_{i + k} E_0 + b_{i + k}) + p_0 E_0 + 1\\ E_i = (\sum p_k a_{i + k} + p_0) E_0 + \sum p_k b_{i + k} + 1\\ a_i = \sum p_k a_{i + k} + p_0, b_i = \sum p_k b_{i + k} + 1\\ Ei=pkEi+k+p0E0+1E0Ei=aiE0+biEi=pk(ai+kE0+bi+k)+p0E0+1Ei=(pkai+k+p0)E0+pkbi+k+1ai=pkai+k+p0,bi=pkbi+k+1

#include <bits/stdc++.h>

using namespace std;

const int N = 510;

double A[N], B[N], p[20];

int n, k1, k2, k3, a, b, c;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int T;
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d %d %d %d %d %d", &n, &k1, &k2, &k3, &a, &b, &c);
    memset(A, 0, sizeof A), memset(B, 0, sizeof B), memset(p, 0, sizeof p);
    p[0] = 1.0 / (k1 * k2 * k3);
    for (int i = 1; i <= k1; i++) {
      for (int j = 1; j <= k2; j++) {
        for (int k = 1; k <= k3; k++) {
          if (i == a && j == b && k == c) {
            continue;
          }
          p[i + j + k] += p[0];
        }
      }
    }
    for (int i = n; i >= 0; i--) {
      for (int j = 3; j <= k1 + k2 + k3; j++) {
        A[i] += p[j] * A[i + j];
        B[i] += p[j] * B[i + j];
      }
      A[i] += p[0];
      B[i] += 1;
    }
    printf("%.15f\n", B[0] / (1 - A[0]));
  }
  return 0;
}

Collecting Bugs

每次共有四种情况发生:

  • 这个 b u g bug bug出现在已有的子系统里,并且在已有的 b u g bug bug里,概率为 i s × i n \frac{i}{s} \times \frac{i}{n} si×ni
  • 这个 b u g bug bug出现在已有的子系统里,但是是一个从未出现的新 b u g bug bug,概率为 i s × n − i n \frac{i}{s} \times \frac{n - i}{n} si×nni
  • 这个 b u g bug bug出现在新的子系统里,但是是一个已有的 b u g bug bug,概率为 s − i s × i n \frac{s - i}{s} \times \frac{i}{n} ssi×ni
  • 这个 b u g bug bug出现在新的子系统里,并且是一个新的 b u g bug bug,概率为 s − i s × n − i n \frac{s - i}{s} \times \frac{n - i}{n} ssi×nni

综上:我们定义 d p [ i ] [ j ] dp[i][j] dp[i][j]表示已经在 i i i个子系统里出现过 j j j b u g bug bug,到在 s s s个子系统里出现过 n n n b u g bug bug的步数期望,

d p [ i ] [ j ] = i × j s × n d p [ i ] [ j ] + i × ( n − j ) s × n d p [ i ] [ j + 1 ] + ( s − i ) × j s × n d p [ i + 1 ] [ j ] + ( s − i ) × ( s − j ) s × n d p [ i + 1 ] [ j + 1 ] dp[i][j] = \frac{i \times j}{s \times n} dp[i][j] + \frac{i \times (n - j)}{s \times n}dp[i][j + 1] + \frac{(s - i) \times j}{s \times n}dp[i + 1][j] + \frac{(s - i) \times (s - j)}{s \times n} dp[i + 1][j + 1] dp[i][j]=s×ni×jdp[i][j]+s×ni×(nj)dp[i][j+1]+s×n(si)×jdp[i+1][j]+s×n(si)×(sj)dp[i+1][j+1]

#include <bits/stdc++.h>

using namespace std;

const int N = 1e3 + 10;

double dp[N][N];

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int n, s;
  while (scanf("%d %d", &n, &s) != EOF) {
    memset(dp, 0, sizeof dp);
    for (int i = n; i >= 0; i--){
      for (int j = s; j >= 0; j--){
          if(i == n && j == s) {
            continue;
          }
          double factor = n * s - i * j;
          dp[i][j] = dp[i + 1][j] * j * (n - i) + dp[i][j + 1] * (s - j) * i + dp[i + 1][j + 1] * (n - i) *(s - j) + n * s;
          dp[i][j] /= factor;
      }
    }
    printf("%.4f\n", dp[0][0]);
  }
  return 0; 
}

Card Collector

容易想到 d p dp dp转移方程 d p [ i ] dp[i] dp[i]表示已经收集了 i i i张卡到收集 n n n张卡所需地步数期望,

d p [ i ] = ∑ p k × d p [ i + k ] + p 0 × d p [ i ] + 1 dp[i] = \sum p_{k} \times dp[i + k] + p_0 \times dp[i] + 1 dp[i]=pk×dp[i+k]+p0×dp[i]+1

d p [ i ] = ∑ p k × d p [ i + k ] + 1 1 − p 0 dp[i] = \frac{\sum p_k \times dp[i + k] + 1} {1 - p_0} dp[i]=1p0pk×dp[i+k]+1

p 0 + ∑ p k = 1 p_0 + \sum p_k = 1 p0+pk=1

然后逆向进行 d p dp dp即可。

#include <bits/stdc++.h>

using namespace std;

const int N = 25;

double dp[1 << 21], p[N];

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int n;
  while (scanf("%d", &n) != EOF) {
    for (int i = 0; i < n; i++) {
      scanf("%lf", &p[i]);
    }
    memset(dp, 0, sizeof dp);
    for (int i = (1 << n) - 2; i >= 0; i--) {
      double delt = 0;
      for (int j = 0; j < n; j++) {
        if (i >> j & 1) {
          continue;
        }
        delt += p[j];
        dp[i] += p[j] * dp[i | (1 << j)];
      }
      dp[i] += 1;
      dp[i] /= delt;
    }
    printf("%.4f\n", dp[0]);
  }
  return 0; 
}

1765 谷歌的恐龙

在每一层我们的期望应该是 a 0 = n × ( n − 1 ) 2 a_0 = \frac{n \times (n - 1)}{2} a0=2n×(n1),我们每一次有 q = n − m n q = \frac{n - m}{n} q=nnm的概率继续游戏,

所以有如下 a 0 , a 0 × q , a 0 × q 2 , a 0 × a 3 , … , a n − 1 × q n − 1 , a n × a n a_0, a_0 \times q, a_0 \times q ^ 2, a_0 \times a ^ 3, \dots,a_{n - 1} \times q ^{n - 1}, a_{n} \times a ^{n} a0,a0×q,a0×q2,a0×a3,,an1×qn1,an×an

a 0 × 1 − q n 1 − q , n a_0 \times \frac{1 - q ^ n}{1 - q}, n a0×1q1qn,n趋于无穷大时, q n = 0 q ^ n = 0 qn=0,有 a 0 1 − q = a 0 m n = n 2 × ( n − 1 ) 2 × m \frac{a_0}{1 - q} = \frac{a_0}{\frac{m}{n}} = \frac{n ^ 2 \times (n - 1)}{2 \times m} 1qa0=nma0=2×mn2×(n1)

所以期望为 n × ( n − 1 ) 2 × m \frac{n \times (n - 1)}{2 \times m} 2×mn×(n1)

#include <bits/stdc++.h>

using namespace std;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  double n, m;
  scanf("%lf %lf", &n, &m);
  printf("%.6f\n", n * (n - 1) / 2 / m);
  return 0;
}

P4550 收集邮票

∑ i = 1 n = n 2 + n 2 所 以 我 们 分 别 求 出 n 2 , n 的 期 望 即 可 , f [ i ] 表 示 从 i 到 n , n 的 期 望 , g [ i ] 表 示 从 i 到 n , n 2 的 期 望 。 n 的 期 望 : f [ i ] = i n ( f [ i ] + 1 ) + n − i n ( f [ i + 1 ] + 1 ) n 2 的 期 望 g [ i ] = i n ( f [ i ] + 1 ) 2 + n − i n ( f [ i + 1 ] + 1 ) 2 f [ i ] 2 = g [ i ] , f [ i + 1 ] 2 = g [ i + 1 ] 化 简 有 : f [ i ] = f [ i + 1 ] + n n − i g [ i ] = g [ i + 1 ] + 2 f [ i + 1 ] + 2 i n − i f [ i ] + n n − i \sum_{i = 1} ^{n} = \frac{n ^ 2 + n}{2}\\ 所以我们分别求出n ^ 2, n的期望即可,f[i]表示从i 到n, n的期望,g[i] 表示从i 到n,n ^ 2的期望。\\ n的期望:\\ f[i] = \frac{i}{n}(f[i] + 1) + \frac{n - i}{n}(f[i + 1] + 1)\\ n ^ 2的期望\\ g[i] = \frac{i}{n}(f[i] + 1) ^ 2 + \frac{n - i}{n}(f[i + 1] + 1) ^ 2\\ f[i] ^ 2 = g[i], f[i + 1] ^ 2 = g[i + 1]\\ 化简有:f[i] = f[i + 1] + \frac{n}{n - i}\\ g[i] = g[i + 1] + 2f[i + 1] + 2\frac{i}{n - i}f[i] + \frac{n}{n - i}\\ i=1n=2n2+nn2,nf[i]in,n,g[i]in,n2n:f[i]=ni(f[i]+1)+nni(f[i+1]+1)n2g[i]=ni(f[i]+1)2+nni(f[i+1]+1)2f[i]2=g[i],f[i+1]2=g[i+1]:f[i]=f[i+1]+ning[i]=g[i+1]+2f[i+1]+2niif[i]+nin

#include <bits/stdc++.h>

using namespace std;

const int N = 1e4 + 10;

double f[N], g[N];

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n;
    scanf("%d", &n);
    for (int i = n - 1; i >= 0; i--) {
      f[i] = f[i + 1] + 1.0 * n / (n - i);
      g[i] = g[i + 1] + 2 * f[i + 1] + 2.0 * i / (n - i) * f[i] + 1.0 * n / (n - i);
    }
    printf("%.2f\n", (f[0] + g[0]) / 2);
    return 0;
}

P3802 小魔女帕琪

#include <bits/stdc++.h>

using namespace std;

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  double a[7], sum = 0;
  for (int i = 0; i < 7; i++) {
    cin >> a[i];
    sum += a[i];
  }
  double ans = 1;
  for (int i = 0; i < 6; i++) {
    ans = ans * (i + 1) * a[i] / (sum - i);
  }
  ans *= a[6];
  printf("%.3f\n", ans * 7.0);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值