1670: 赌神的战斗
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 20 Solved: 5
[ Submit][ Status][ Web Board]
Description
老千可以有很多,但是赌神,只能有一个!
2015届赌神争霸赛现在在湖南长沙淹鱼塘隆重开幕,2名赌神候选者已经准备就绪。
已知赌神争霸的规则如下:
每个赌神候选者有一个他特制的骰子和特制的战甲,分别能给他提供攻击力和生命值。
两个赌神候选者交手的流程如下:
1,2号赌神候选者分别投掷自己的骰子,点数相同则重新投,否则点数大的赌神候选者会对点数小的造成他们点数差的伤害。如果承受伤害之后生命值小于或等于零,则战败。否则,进行下一轮交手。(投掷出来的点数在
上
均匀分布)
Input
多组数据,第一行有一个整数
T
,表示有
T
组数据。(
T<=100
)
以下每组数据
每行
有
四
个整数
ATK1,HP1
和
ATK2,HP2
,
ATK1和HP1
表示
1号赌神
候选者
的骰子最大点数和他的血量,ATK2和HP2
表示
2号赌神
候选者
的骰子最大点数和他的血量
。
(1<=
ATK1
,
HP1
,
ATK2
,
HP2
<=
200
)
Output
两个浮点数(精确到小数点后三位),为1号赌神的胜率和2号赌神的胜率。
Sample Input
2
6 1 6 1
1 24 2 1
Sample Output
0.500 0.500
0.000 1.000
HINT
Source
很直接的概率dp
dp[i][j]代表赌神a有i血,赌神b有j血时赌神a的胜率
显然dp[i][0]其中i不等于0的概率应该是1,因为此时赌神a已经赢了
显然dp[o][j]应该是0
这个问题最开始用的是这个很直接的代码
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int M=205;
double p[M][M];
int main()
{
int t;
int h1,h2;
int aa1,aa2;
double a1,a2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&aa1,&h1,&aa2,&h2);
if(aa1==1&&aa2==1)
{
printf("0.000 0.000\n");
continue;
}
if(aa1==1&&aa2!=1)
{
printf("0.000 1.000\n");
continue;
}
if(aa2==1&&aa1!=1)
{
printf("1.000 0.000\n");
continue;
}
memset(p,0,sizeof(p));
for(int i=1;i<=h1;i++)
p[i][0]=1;
a1=aa1;a2=aa2;
int tp;
if(aa1>aa2)
tp=aa2;
else
tp=aa1;
double pp=aa1*aa2-tp;
for(int i=1;i<=h1;i++)
{
for(int j=1;j<=h2;j++)
{
for(int p1=1;p1<=aa1;p1++) //穷举扔色子的情况
{
for(int p2=1;p2<=aa2;p2++)
{
if(p1==p2)
{
tp++;
continue;
}
if(p1>p2)
{
if(j-p1+p2<=0)
p[i][j]+=p[i][0];
else
p[i][j]+=p[i][j-p1+p2];
}
if(p1<p2)
{
if(i-p2+p1>0)
p[i][j]+=p[i-p2+p1][j];
}
//cout<<tp<<endl;
//cout<<p1<<" "<<p2<<" "<<p[i][j]<<endl;
}
}
p[i][j]=p[i][j]/pp;
}
}
printf("%.3lf %.3lf\n",p[h1][h2],1-p[h1][h2]);
}
return 0;
}
原因很简单,其实两个人每次扔完扣多少血的概率是固定的
因此可以初始化一个系数矩阵
这样每次只要针对扣血的情况而不是投色子的情况处理即可
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int M=205;
double p[M][M];
double pp[M][2];
int main()
{
int t;
int h1,h2;
int aa1,aa2;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&aa1,&h1,&aa2,&h2);
if(aa1==1&&aa2==1)
{
printf("0.000 0.000\n");
continue;
}
if(aa1==1&&aa2!=1)
{
printf("0.000 1.000\n");
continue;
}
if(aa2==1&&aa1!=1)
{
printf("1.000 0.000\n");
continue;
}
memset(p,0,sizeof(p));
memset(pp,0,sizeof(pp));
for(int i=1;i<=h1;i++)
p[i][0]=1;
int tp,tpma;
if(aa1>aa2)
{
tp=aa2;
tpma=aa1;
}
else
{
tp=aa1;
tpma=aa2;
}
double ppp=aa1*aa2-tp;
for(int p1=1;p1<=aa2;p1++) //这个位置需要用矩阵做优化
{
for(int p2=1;p2<=aa1;p2++) //初始化系数矩阵
{
if(p1>p2)
pp[p1-p2][0]+=1;
if(p1<p2)
pp[p2-p1][1]+=1;
//cout<<tp<<endl;
//cout<<p1<<" "<<p2<<" "<<p[i][j]<<endl;
}
}
for(int i=1;i<=h1;i++)
{
for(int j=1;j<=h2;j++)
{
for(int k=1;k<=tpma;k++)
{
if(k<=i)
p[i][j]+=pp[k][0]*p[i-k][j];
if(k<=j)
p[i][j]+=pp[k][1]*p[i][j-k];
else
p[i][j]+=pp[k][1]*p[i][0];
}
p[i][j]=p[i][j]/ppp;
}
}
printf("%.3lf %.3lf\n",p[h1][h2],1-p[h1][h2]);
}
return 0;
}