原题: https://cn.vjudge.net/problem/Gym-101954G
题意:
8*8的棋盘,已知两个马(走日,无马脚,每次往各个可行方向走的概率相同)的位置,黑马先走,吃法同中国象棋,问黑马赢的概率大还是白马
解析:
直接暴力每次走完后落在64个格子上的概率
设:当前由
,
有
个方向可以走,当前马的概率为
,对面马的概率
那么显然此时获胜的的概率为:
接下来是难点,怎么维护
对于任何一个
可以走到的点的概率就直接是
吗?实则不然,因为如果上一次对面和落在
,也就是说之前我已经赢了,那么这部分情况是没有后续的,所以,概率应该是
#include<bits/stdc++.h>
using namespace std;
typedef double F;
F a[8][8],b[8][8];
const double eps = 1e-6;
int di[8][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{-2,1},{2,-1},{-2,-1}};
F val[8][8];
void init(){
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
int co=0;
for(int k=0;k<8;k++){
int x=i+di[k][0],y=j+di[k][1];
if(x<0||x>=8||y<0||y>=8)continue;
co++;
}
val[i][j]=1.0/(F)co;
}
}
}
int main(){
init();
int aa,ab,c,d;cin>>aa>>ab>>c>>d;
a[aa-1][ab-1]=1,b[c-1][d-1]=1;
F v1=0,v2=0;
bool f=0;
while(1){
F aa[8][8],bb[8][8];
memset(aa,0,sizeof(aa));
memset(bb,0,sizeof(bb));
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
for(int k=0;k<8;k++){
int x=i+di[k][0],y=j+di[k][1];
if(x<0||x>=8||y<0||y>=8)continue;
aa[x][y]+=a[i][j]*val[i][j]*(1.0-b[i][j]);
}
}
}
//double S=0;
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
a[i][j]=aa[i][j];
//S+=a[i][j];
v1+=a[i][j]*b[i][j];
}
}
//printf("%.5f\n",S);
if(v1-0.5>eps){
f=1;printf("white\n");break;
}
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
for(int k=0;k<8;k++){
int x=i+di[k][0],y=j+di[k][1];
if(x<0||x>=8||y<0||y>=8)continue;
bb[x][y]+=b[i][j]*val[i][j]*(1.0-a[i][j]);
}
}
}
for(int i=0;i<8;i++){
for(int j=0;j<8;j++){
b[i][j]=bb[i][j];
v2+=a[i][j]*b[i][j];
}
}
if(v2-0.5>eps){
f=1;printf("black\n");break;
}
}
if(!f)printf("draw\n");
}