CSUOJ 赌神的战斗

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

分析:

概率DP。用两者的血量为下标建立二维DP数组,并预处理玩家1和玩家2被扣血量x时的概率分别为g1[x]、g2[x]。状态转移dp[i][j]+=dp[i][j+q]*g1[q]+dp[i+p][j]*g2[p遍历完所有的q、p之后再除去平局的情况:dp[i][j]=dp[i][j]/(1-g1[0]) 这里g1[0]和g2[0]都行,是相等的。

下面是代码:(我觉得自己的代码一直都是无比暴力的。。。)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
double g1[500],g2[500];
double dp[500][500];
 
int t,h1,h2,k1,k2;
 
void init()
{
    memset(g1,0,sizeof(g1));
    memset(g2,0,sizeof(g2));
    double p1,p2;
    p1=(double)1.0/k1;
    p2=(double)1.0/k2;
    for(int i=1;i<=k1;++i){
        for(int j=1;j<=k2;++j){
            if(i>j)g2[i-j]+=p1*p2;
            else if(i<j)g1[j-i]+=p1*p2;
            else{g1[0]+=p1*p2;g2[0]+=p1*p2;}
        }
    }
}
 
int main()
{
 ///   freopen("in.txt","r",stdin);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d",&k1,&h1,&k2,&h2);
        if(k1==1&&k2==1){
            printf("0.000 0.000\n");
            continue;
        }
        memset(dp,0,sizeof(dp));   init();
        dp[h1][h2]=1.0;
        double vic1,vic2;
        vic1=0.0;vic2=0.0;
        for(int i=h1;i>0;--i){
            for(int j=h2;j>0;--j){
                for(int k=1;k<=k1;++k){
                    dp[i][j]+=dp[i][j+k]*g2[k];
                }
                for(int k=1;k<=k2;++k){
                    dp[i][j]+=dp[i+k][j]*g1[k];
                }
                if(i!=h1||j!=h2)dp[i][j]=dp[i][j]/(1-g1[0]);///***这一步很重要
            }
            for(int k=1;k<=k1;++k){
                for(int b=1;b<=k;++b){
                    dp[i][0]+=dp[i][b]*g2[k];
                }
            }
            dp[i][0]=dp[i][0]/(1-g1[0]);**这一步很重要
            vic1+=dp[i][0];
        }
        for(int j=1;j<=h2;++j){
            for(int k=1;k<=k2;++k){
                for(int b=1;b<=k;++b){
                    dp[0][j]+=dp[b][j]*g1[k];
                }
            }
            dp[0][j]=dp[0][j]/(1-g1[0]);///***这一步很重要
            vic2+=dp[0][j];
        }
        printf("%.3lf %.3lf\n",vic1,vic2);
    }
    return 0;
}
 
/**************************************************************
    Problem: 1670
    User: 504772261
    Language: C++
    Result: Accepted
    Time:2408 ms
    Memory:2924 kb
****************************************************************/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值