#include<bits/stdc++.h>
using namespace std;
int cnt[2][10];//攻击次数
int hp[2][10], atk[2][10], n[2], dead[2];
double win[3], res[3];//win0:0赢的概率,win1:1赢的概率,win2:平局的概率
void dfs(int op, double p){//当前轮到op攻击,此时概率为p
if(dead[op] == n[op] && dead[op ^ 1] == n[op ^ 1]){
win[2] += p;//分步加法
return;
}
if(dead[op] == n[op]){
win[op ^ 1] += p;
return;
}
if(dead[op ^ 1] == n[op ^ 1]){
win[op] += p;
return;
}
int minn = 1e9;
for(int i = 1; i <= n[op]; i++){
if(hp[op][i] > 0 && cnt[op][i] < minn) minn = cnt[op][i];
}
int id, id2;
for(int i = 1; i <= n[op]; i++){
if(hp[op][i] > 0 && cnt[op][i] == minn){
id = i;//找最左的攻击次数最少的人来发动攻击
break;
}
}
int rest = n[op ^ 1] - dead[op ^ 1];
double pp = 1.0 / rest;//选到某个攻击对象的概率
for(int i = 1; i <= n[op ^ 1]; i++){
if(hp[op ^ 1][i] > 0){
bool f = 0, f2 = 0;
hp[op ^ 1][i] -= atk[op][id];
if(hp[op ^ 1][i] <= 0) dead[op ^ 1]++, f = 1;
hp[op][id] -= atk[op ^ 1][i];
if(hp[op][id] <= 0) dead[op]++, f2 = 1;
cnt[op][id]++;
dfs(op ^ 1, p * pp);//分步乘法
//回溯,恢复
if(hp[op][id] <= 0) dead[op]--;
if(hp[op ^ 1][i] <= 0) dead[op ^ 1]--;
hp[op ^ 1][i] += atk[op][id];
hp[op][id] += atk[op ^ 1][i];
cnt[op][id]--;
}
}
}
int main()
{
int i;
cin >> n[0] >> n[1];
for (i = 1; i <= n[0]; i++)
{
cin >> hp[0][i];
atk[0][i] = hp[0][i];
}
for (i = 1; i <= n[1]; i++)
{
cin >> hp[1][i];
atk[1][i] = hp[1][i];
}
if(n[0] == n[1]){
dfs(0, 1);//可能0先手
for(int i = 0; i <= 2; i++){
res[i] += win[i] / 2;//概率权重为1/2
win[i] = 0;
}
dfs(1, 1);//可能1先手
for(int i = 0; i <= 2; i++){
res[i] += win[i] / 2;//概率权重为1/2
}
}
else{
if(n[0] > n[1]){
dfs(0, 1);
}
else dfs(1, 1);
for(int i = 0; i <= 2; i++){
res[i] = win[i];
}
}
cout << fixed << setprecision(15) << res[0] << '\n';
cout << fixed << setprecision(15) << res[1] << '\n';
cout << fixed << setprecision(15) << res[2] << '\n';
}
dfs模拟算概率
最新推荐文章于 2024-11-14 15:56:18 发布