Gym

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
", dp1[n][n], dp2[n][n]);
    }
}
原文地址:https://www.cnblogs.com/hznumqf/p/13547355.html