POJ 1280 Game

Recently, there was an international volleyball championship. Speaking of volleyball, we are interested in the probability of winning of one or another team, if we know some information about the teams. Here are the rules of the game and the necessary information: 
  • the match is played by two teams: A and B; 
  • the first team to win K games in a match, wins the match; 
  • each game consists of rounds; each round is won by one of the teams, and the team adds one point to its score for the current game; 
  • the first team to win L points in a game, wins the game; 
  • if team A serves the ball in a round, it has Pa% chance to win the round (and (100-Pa)% to loose it); 
  • if team B serves the ball in a round, it has Pb% chance to win the round (and (100-Pb)% to loose it); 
  • if a round is not the first in a game, the ball in the round is served by the team that won the last round; 
  • if a game is not the first in a match, the ball in the first round of the game is served by the team that did not served the ball in the first round of the previous game; 
  • both teams have an equal chance to serve the ball in the first round of the very first game of a match. 
    So, for given values of Pa, Pb, K, and L, you have to compute the probability, as a percent, for team A to win the match. 

Input

There is one number in the first line ? the number of data sets. Each data set consists of a single line with four integers on it: Pa, Pb, K, and L (1<= K<=100, 1<= L<=100).

Output

For each test you must write on one line the required result with exactly one digit after the decimal point (the number should be rounded to the first digit after the decimal point). 

Sample Input

2
100 50 1 3
100 1 1 1

Sample Output

93.8
99.5
题意:由两个队进行的比赛,比赛由若干场组成,每一场比赛又由若干轮组成,任何一个队每赢得一分就赢得了这一轮,率先赢得L轮的队就赢得了这场比赛,率先赢得K场比赛的队就赢得了这次比赛。
如果A队在这一轮持有球,那么A队就有Pa%的概率赢得这轮,1-pa%输掉,如果B队在这轮中持有球,B队有Pb%的概率赢得这轮,1-Pb%输掉。
如果这一轮不是这场比赛的第一轮,球由上一轮的赢家持有。如果这一场不是这个比赛的第一场,在第一轮中,球由上一场比赛中的第一轮中的没有持有球的那一队持有。
两个球队各有50%的几率在第一场比赛的第一轮中持有球。
问的是A队赢得这个比赛的概率。


思路:由于问题是求A赢得整个比赛的概率,而整个比赛又是由K场小比赛组成,而每场小比赛又是由L轮小小比赛组成。而题目给出的条件是A,B在拥有球的情况下赢得一轮比赛的概率,而第一场的第一轮A,B拥有球的情况未知(事实上各占50%)所以从每一轮入手:
dpa(i,j,0),dpa(i,j,1)分别表示A最开始拥有球而且赢得\输掉第i轮比赛,B赢得第j轮比赛的概率。
dpb(I,j,0),dpb(i,j,1)分别表示B最开始拥有球而且赢得\输掉第i轮比赛,B赢得第j轮比赛的概率。
上面两个状态的区别仅仅在于那一个队在一开始拥有球。其他无异;
以dpa为例:由于A赢得一轮有可能是A在上一轮赢了,而且在pa的概率下又赢了,或者是在上一轮输了,但是B在这轮没有赢。
所以有状态转移方程:dpa(i,j,0)=dpa(i-1,j,0)*pa+dpa(i-1,j,1)*(1-pb);
A输球的情况与赢得情况类似。
最后将A分别在初始情况下有球和没球的情况下赢得L场的概率加起来就是A赢L场而且在L轮的时候拥有球的概率;
由于在比赛开最始时两个队得到球的概率一样,DPA(i,j)表示A赢了i场,B赢了j场的概率;所以DPA就有两个来源:A赢i-1场,B赢j场,而且A赢了;或者是A赢i场,B赢j-1场,而且B赢了;由于每一场的初始情况不确定,A赢球的概率用PX=b[(i+j+1)]震荡表示。所以有状态转移方程:DPA(i,j)=PDA(i-1,j)*px+PDA(i,j-1)*(1-px);
DPB的情况与DPA类似。
最后将A赢k场B赢0~k-1场的概率加起来为ans;
AC代码:
//
//  main.cpp
//  poj1280
//
//  Created by Charles on 2017/7/7.
//  Copyright © 2017年 Charles. All rights reserved.
//

#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
const int maxn = 101;
double dpa[maxn][maxn][2],dpb[maxn][maxn][2],DPA[maxn][maxn],DPB[maxn][maxn],PA,PB,b[2],PX,ans;
int pa,pb,k,L,t;
int main(int argc, const char * argv[]) {
    cin>>t;
    while(t--){
        memset(dpa, 0, sizeof(dpa));
        memset(dpb, 0, sizeof(dpb));
        memset(DPA, 0, sizeof(DPA));
        memset(DPB, 0, sizeof(DPB));
        dpa[0][0][0]=1; dpa[0][0][1]=0; dpb[0][0][0]=0; dpb[0][0][1]=1;
        cin>>pa>>pb>>k>>L;
        double Pa=pa/100.0; double Pb=pb/100.0;
        for(int i=0;i<=L;++i){
            for(int j=0;j<L;++j){
                if(i==0 && j==0) continue;
                dpa[i][j][0]=0;
                if(i!=0) dpa[i][j][0]+=(dpa[i-1][j][0]*Pa+dpa[i-1][j][1]*(1-Pb));
                if(i<L){
                    dpa[i][j][1]=0;
                    if(j!=0) dpa[i][j][1]+=(dpa[i][j-1][0]*(1-Pa)+dpa[i][j-1][1]*Pb);
                }
            }
        }
        for(int i=0;i<=L;++i){
            for(int j=0;j<L;++j){
                if(i==0 && j==0) continue;
                dpb[i][j][0]=0;
                if(i!=0) dpb[i][j][0]+=(dpb[i-1][j][0]*Pa+dpb[i-1][j][1]*(1-Pb));
                if(i<L){
                    dpb[i][j][1]=0;
                    if(j!=0) dpb[i][j][1]+=(dpb[i][j-1][0]*(1-Pa)+dpb[i][j-1][1]*Pb);
                }
            }
        }
        PA=0;   PB=0;
        for(int i=0;i<L;++i) PA+=dpa[L][i][0];
        for(int i=0;i<L;++i) PB+=dpb[L][i][0];
        
        b[0]=PA;   b[1]=PB;
        DPA[0][0]=0.5;  DPB[0][0]=0.5;
        for(int i=0;i<k;++i){
            for(int j=0;j<k;++j){
                if(i==0 && j==0) continue;
                PX=b[(i+j+1)%2];
                DPA[i][j]=0;
                if(i>0) DPA[i][j]+=DPA[i-1][j]*PX;
                if(j>0) DPA[i][j]+=DPA[i][j-1]*(1-PX);
            }
        }
        
        for(int i=0;i<k;++i){
            PX=b[(k+i+1)%2];
            DPA[k][i]+=DPA[k-1][i]*PX;
        }
        
        for(int i=0;i<k;++i){
            for(int j=0;j<k;++j){
                if(i==0 && j==0) continue;
                PX=b[(i+j)%2];
                DPB[i][j]=0;
                if(i>0) DPB[i][j]+=DPB[i-1][j]*PX;
                if(j>0) DPB[i][j]+=DPB[i][j-1]*(1-PX);
            }
        }
        
        for(int i=0;i<k;++i){
            PX=b[(k+i)%2];
            DPB[k][i]+=DPB[k-1][i]*PX;
        }
        
        ans=0;
        for(int i=0;i<k;++i) ans+=DPA[k][i];
        for(int i=0;i<k;++i) ans+=DPB[k][i];
        ans*=100;
        printf("%.1lf\n", ans);
        cout<<PA<<" "<<PB<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值