题解:P17212 [ICPC 2017 Nanning R] Attacker-Defender Game
lailai0916 · · 题解
题意简述
进攻方与防守方每回合同时选择消耗的能量。比较结果决定防守方生命值的增减,并扣除相应能量。求双方采用最优混合策略时,进攻方的获胜概率。
解题思路
设
只讨论
每个后继状态的
先排除取值为
固定防守方本回合选择的
若每一列至少有一个正元素,进攻方给所有行动分配正概率,就能保证期望收益为正;若某列全为零,防守方固定选择该列即可。因此:
当
答案恰为
必要性可对
只对满足:
的状态求解矩阵博弈。
剩余状态通过线性规划求解矩阵博弈。令
若最优目标值为
约束右端均为
阈值预处理为
参考代码
#include <bits/stdc++.h>
using namespace std;
using ld=long double;
const int N=55;
const int Q=1205;
const ld eps=1e-15L;
ld f[N][N][N],g[N][N],p[N][N];
int need[N][N],q[Q][3],bs[N],nb[N];
void pivot(int r,int s,int m,int n)
{
ld inv=1/p[r][s];
for(int i=0;i<=m;i++)
{
if(i==r)continue;
for(int j=0;j<=n;j++)
{
if(j==s)continue;
p[i][j]-=p[r][j]*p[i][s]*inv;
}
}
for(int i=0;i<=n;i++)if(i!=s)p[r][i]*=inv;
for(int i=0;i<=m;i++)if(i!=r)p[i][s]*=-inv;
p[r][s]=inv;
swap(bs[r],nb[s]);
}
ld simplex(int m,int n)
{
for(int i=0;i<m;i++)
{
bs[i]=n+i;
p[i][n]=1;
for(int j=0;j<n;j++)p[i][j]=g[i][j]+1;
}
for(int i=0;i<n;i++)
{
nb[i]=i;
p[m][i]=-1;
}
p[m][n]=0;
while(1)
{
int s=-1;
for(int i=0;i<n;i++)
{
if(p[m][i]<-eps&&(s==-1||nb[i]<nb[s]))s=i;
}
if(s==-1)return p[m][n];
int r=-1;
for(int i=0;i<m;i++)
{
if(p[i][s]<=eps)continue;
if(r==-1)
{
r=i;
continue;
}
ld x=p[i][n]/p[i][s],y=p[r][n]/p[r][s];
if(x<y-eps||(fabsl(x-y)<=eps&&bs[i]<bs[r]))r=i;
}
if(r==-1)return p[m][n];
pivot(r,s,m,n);
}
}
ld get(int h,int d,int a)
{
if(!h)return 1;
if(a<h)return 0;
if(!d)return 1;
return f[h][d][a];
}
ld calc(int h,int d,int a)
{
if(a<need[h][d])return 0;
if(a>=h+d)return 1;
for(int i=1;i<=a;i++)
{
for(int j=1;j<=d;j++)
{
if(i>j)g[i-1][j-1]=get(h-1,d,a-i);
else if(i<j)g[i-1][j-1]=get(h+1,d-j,a);
else g[i-1][j-1]=get(h,d-j,a-i);
}
}
ld z=simplex(a,d);
return max(0.0L,min(1/z-1,1.0L));
}
void init(int md,int ma)
{
int inf=ma+1;
for(int i=0;i<=ma+1;i++)
{
for(int j=0;j<=md;j++)need[i][j]=inf;
}
for(int i=0;i<=md;i++)need[0][i]=0;
for(int i=1;i<=ma+1;i++)need[i][0]=min(i,inf);
for(int i=1;i<=md;i++)
{
for(int j=1;j<=ma;j++)
{
int mx=0;
for(int k=1;k<=i;k++)
{
int mn=min(k+1+need[j-1][i],k+need[j][i-k]);
if(k>=2)mn=min(mn,need[j+1][i-k]);
mx=max(mx,min(mn,inf));
}
need[j][i]=mx;
}
}
for(int i=2;i<=ma+md;i++)
{
for(int j=1;j<=ma;j++)
{
int d=i-j;
if(d<1||d>md)continue;
for(int k=1;k<=j;k++)f[k][d][j]=calc(k,d,j);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
int md=0,ma=0;
for(int i=0;i<T;i++)
{
cin>>q[i][0]>>q[i][1]>>q[i][2];
md=max(md,q[i][1]);
ma=max(ma,q[i][2]);
}
init(md,ma);
cout<<fixed<<setprecision(6);
for(int i=0;i<T;i++)cout<<get(q[i][0],q[i][1],q[i][2])<<'\n';
return 0;
}