2019 华南理工大学“三七互娱杯”程序设计竞赛 解题报告
Problem B:HRY and codefire (概率 DP)
链接:https://ac.nowcoder.com/acm/contest/874/A
题意:有两个初始等级为0的账号打题,开局任选一账号。每一次答题,若AC一题该账号升一级,且下一轮继续使用当前账号。反之,当前账号不降级,下一轮使用另一个账号。如此反复,直到其中一个账号达到n级,结束打题。现已知任一账号在等级为 i 的胜率为 pi ,求达成结束打题条件的期望局数。
题解:1.状态设定;设dp(i,j)的状态为当前账号的等级分别为 i 、 j,且下一轮使用等级为 i 的账号达到 n 级所需的期望局数。
2.初始化;毫无疑问,任一账号达到 n 级后就不需要再继续打题了,所以用 dp(i,n) = dp(n,i) = 0 (0 <= i < n)来表示任一账号达到 n 级时,另一账号无论多少级,所需的期望局数都为0。
3.状态转移方程;对于dp(i,j),我们所需的期望局数为【当前进行的这一局】+ pi【赢了后的期望局数】 + (1-pi)【输了后的期望局数】,即1 + pi*dp(i+1,j) + (1-pi)*dp(j,i)
4.计算;两个循环求出 dp(i,j)、dp(j,i),最后 dp(0,0)即为我们要知道的结果。这里需要注意的是上面的式子存在环,需要用换元法得到可以直接使用的式子。
#include <bits/stdc++.h> using namespace std; int main() { int t; scanf("%d",&t); while (t--) { int n; scanf("%d",&n); double p[n]; for (int i=0;i<n;i++) { scanf("%lf",&p[i]); } double dp[n+1][n+1]; for (int i=0;i<=n;i++) { dp[n][i] = dp[i][n] = 0; } for (int i=n-1;i>=0;i--) { for (int j=n-1;j>=0;j--) { dp[i][j] = (1.0 + p[i]*dp[i+1][j] + (1.0-p[i])*(p[j]*dp[j+1][i] + 1.0)) \ / (1.0 - (1.0-p[i])*(1.0-p[j])); dp[j][i] = (1.0 + p[j]*dp[j+1][i] + (1.0-p[j])*(p[i]*dp[i+1][j] + 1.0)) \ / (1.0 - (1.0-p[i])*(1.0-p[j]));; } } printf("%.4f\n",dp[0][0]); } return 0; }

浙公网安备 33010602011771号