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]);
}
}