3 4 1 1 5 1 5 5 2 1
Case #1: 0.250000 Case #2: 0.000000 Case #3: 0.217626
因为要考虑连续赢的情况并且每次动作只和第一个人有关,设第一维表示第一个人连续赢的次数。第二维表示第j个人此次赢的概率。
dp[i][j]表示第一个人已经赢了i次,当前第j个人能赢的概率。
最终也就是要求dp[0][k].表示第一个人一次都没赢时第k个人赢的概率。
当j=1时,dp[i][j]=1/4*dp[i+1][j]+3/4*dp[1][n-2] //该人要么赢,要么输,输的话,后面有两个人排在他后面,所以他在n-2的位置。
当j=2时,dp[i][j]=1/4*dp[i+1][n-2]+1/4*dp[1][j-1]+2/4*dp[1][n-1]
当j=3时,dp[i][j]=1/4*dp[i+1][n-1]+1/4*dp[1][n-1]+1/4*dp[1][1]+1/4*dp[1][n]
当j=4时,dp[i][j]=1/4*dp[i+1][n]+2/4*dp[1][n]+1/4*dp[1][1];
当j>4时,dp[i][j]=1/4*dp[i+1][j-3]+3/4*dp[1][j-3]
注意
1、i<m,
2、dp[m][1]=1,表示第一个人已经赢了m次,结束。
此转移方程,前后都有,不能直接通过递推或迭代求出,所以选用高斯消元求解。
一共有m*n个未知数,所以可以求一个n*m元的一次方程。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> using namespace std; #define maxn 102 #define eps 1e-10 double g[maxn][maxn]; double x[maxn]; int n,m,k; void add(int cnt,int i,int j,double val) { int t=i*n+j; if(i==m) { if(j==1) //p[m][1]=1;结束 g[cnt][m*n+1]+=-1.0*val; //方程的右边 return; } g[cnt][t]+=val; } void gauss(int n,int m) { int row,col,i,j,k; for(row=1,col=1;row<n,col<m;row++,col++) { k=row; for(i=row+1;i<=n;i++) //列主元 if(fabs(g[i][col])>fabs(g[k][col])) k=i; if(k!=row) //行交换 { for(i=col; i<=m; i++) swap(g[k][i],g[row][i]); } for(i=row+1; i<=n; i++) //主元不是0把下面的行第一个值全部变为0 { if(fabs(g[i][col])<eps) continue; double t=g[i][col]/g[row][col]; g[i][col]=0.0; for(j=col+1;j<=m;j++) g[i][j]-=t*g[row][j]; } } for(i=n;i>=1;i--) //回代求解 { x[i]=g[i][m]; for(j=i+1;j<=n;j++) x[i]-=x[j]*g[i][j]; x[i]/=g[i][i]; } } int main() { int i,j,cs,nn=0; scanf("%d",&cs); while(cs--){ scanf("%d%d%d",&n,&m,&k); memset(g,0,sizeof(g)); int cnt=0; for(i=0;i<m;i++) //i==m的时候只能在右边出现 for(j=1;j<=n;j++) { cnt++; add(cnt,i,j,1.0); if(j==1) { add(cnt,i+1,j,-0.25); add(cnt,1,n-2,-0.75); } else if(j==2) { add(cnt,i+1,n-2,-0.25); add(cnt,1,1,-0.25); add(cnt,1,n-1,-0.5); } else if(j==3) { add(cnt,i+1,n-1,-0.25); add(cnt,1,1,-0.25); add(cnt,1,n-1,-0.25); add(cnt,1,n,-0.25); } else if(j==4) { add(cnt,i+1,n,-0.25); add(cnt,1,n,-0.5); add(cnt,1,1,-0.25); } else { add(cnt,i+1,j-3,-0.25); add(cnt,1,j-3,-0.75); } } gauss(cnt,cnt+1); printf("Case #%d: %.6lf\n",++nn,x[k]); } return 0; }