Loading

Gym - 102470D Darts 概率DP,思维

Gym - 102470D Darts 概率DP,思维

题意

\(A,B\) 两人轮流扔飞镖,初始分数均为\(N\) ,若射中的分数小于当前分数,则当前分数减去该分数,否则分数不变。

现使得分数为\(0\) 的获胜,

\(A\) 随机扔飞镖,每块的概率相等。

\(B\) 可以贪心的选择三块区域扔飞镖,每块的概率\(1/3\)

标靶的权值是固定的$1 $ 到 $20 $

给定\(N\) ,问\(A\)\(B\) 先手分别可以获胜的概率

分析

此题引入了两个对象,也就是说每个人的状态会受到另一个的影响,还挺有意思的。

首先需要注意到的是若两个人的分数都小于\(20\) ,那不论大小多少概率都是定值,因为仅当仍中与当前分数相等的时候才会获胜,和扔到多少无关。这是必须注意到的性质,至于是多少可以直接从样例复制。

\(dp1[i][j]\) 表示\(A\) 的分数为\(i\) ,\(B\) 的分数为\(j\)\(A\) 先手获胜的概率,\(dp2[i][j]\) 也同理。

转移方程

\[dp1[i][j] = \sum_{k=0}^{k<20}(1-dp2[get(i,sc[k])][j])/20 \\ dp2[i][j] = max(dp2[i][j],(3 - dp1[i][get(j,x)] - dp1[i][get(j,y)]-dp1[i][get(j,z)])/3) \]

实现时注意转移的先后顺序(很重要!)

const int sc[] = { 20,1,18,4,13,6,10,15,2,17,3,19,7,16,8,11,14,9,12,5 };

int get(int x, int y) {
    return y <= x ? x - y : x;
}

double dp1[510][510], dp2[510][510];
void init() {
    for (int i = 1; i <= 20; i++) for (int j = 1; j <= 20; j++) dp1[i][j] = 0.136363636364, dp2[i][j] = 0.909090909091;
    for (int i = 1; i < 510; i++) {
        for (int j = 1; j < 510; j++) {
            if (i <= 20 && j <= 20) continue;
            if (i <= 20) {
                for (int k = 0; k < 20; k++) {
                    int y = (k + 1) % 20, z = (k + 2) % 20;
                    double tmp1 = dp1[i][get(j, sc[k])];
                    double tmp2 = dp1[i][get(j, sc[y])];
                    double tmp3 = dp1[i][get(j, sc[z])];
                    dp2[i][j] = max(dp2[i][j], (3 - tmp1 - tmp2 - tmp3) / 3.0);
                }
                for (int k = 0; k < 20; k++) {
                    dp1[i][j] += (1 - dp2[get(i, sc[k])][j]) / 20;
                }
            }
            else {
                for (int k = 0; k < 20; k++) {
                    dp1[i][j] += (1 - dp2[get(i, sc[k])][j]) / 20;
                }
                for (int k = 0; k < 20; k++) {
                    int y = (k + 1) % 20, z = (k + 2) % 20;
                    double tmp1 = dp1[i][get(j, sc[k])];
                    double tmp2 = dp1[i][get(j, sc[y])];
                    double tmp3 = dp1[i][get(j, sc[z])];
                    dp2[i][j] = max(dp2[i][j], (3 - tmp1 - tmp2 - tmp3) / 3.0);
                }
            }
        }
    }
}

int main() {
    init();
    int n;
    while (n = readint()) {
        if (!n) break;
        printf("%.10f %.10f\n", dp1[n][n], dp2[n][n]);
    }
}
posted @ 2020-08-22 21:57  MQFLLY  阅读(203)  评论(0编辑  收藏  举报