Snakes and Ladders LightOJ - 1151
从第 1 1 1 个格子走到第 100 100 100 个格子,每次走的步数由扔筛子决定,假如超过 100 100 100 就重新扔。其中有些格子可以跳到另外一些格子。问走到第 100 100 100 个格子需要扔筛子次数的期望是多少?
用 d p [ i ] dp[i] dp[i] 来表示第 i i i 个格子的期望数,则有三种情况:
(1)第 i i i 个格子不发生跳转,且扔筛子不会越界:
d p [ i ] = 1 + 1 6 ∑ j = 1 6 d p [ i + j ] dp[i]=1+\frac{1}{6}\sum_{j=1}^{6}dp[i+j] dp[i]=1+61j=1∑6dp[i+j]
(2)第 i i i 个格子不发生跳转,但是扔筛子会越界:
d p [ i ] = 1 + 1 6 [ ∑ j = 1 100 − i d p [ i + j ] + ∑ j = 1 6 + i − 100 d p [ i ] ] dp[i]=1+\frac{1}{6}[\sum_{j=1}^{100-i}dp[i+j]+\sum_{j=1}^{6+i-100}dp[i]] dp[i]=1+61[j=1∑100−idp[i+j]+j=1∑6+i−100dp[i]]
(3)第 i i i 个格子发生跳转,跳转到 k k k:
d p [ i ] = d p [ k ] dp[i]=dp[k] dp[i]=dp[k]
可以列出有 100 100 100 个方程, 100 100 100 个变量的方程组,用高斯消元法进行求解。
代码如下(高斯消元法的模板改自kuangbin):
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
//#define WINE
#define MAXN 105
#define eps 1e-9
using namespace std;
double a[MAXN][MAXN],x[MAXN];
bool m[MAXN];
int equ=100,var=100,T,iCase,n;
int Gauss(){
int i,j,k,col,max_r;
for(k=0,col=0;k<equ&&col<var;k++,col++){
max_r=k;
for(i=k+1;i<equ;i++)
if(fabs(a[i][col])>fabs(a[max_r][col]))
max_r=i;
if(fabs(a[max_r][col])<eps)return 0;
if(max_r!=k)swap(a[max_r],a[k]),swap(x[max_r],x[k]);
for(j=col+1;j<var;j++)a[k][j]/=a[k][col];
x[k]/=a[k][col];a[k][col]=1;
for(i=0;i<equ;i++){
if(i==k)continue;
for(j=col+1;j<var;j++)a[i][j]-=a[i][col]*a[k][j];
x[i]-=a[i][col]*x[k];
a[i][col]=0;
}
}
return 1;
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
memset(m,false,sizeof(m));
memset(a,0,sizeof(a));
memset(x,0,sizeof(x));
scanf("%d",&n);
while(n--){
int i,j;
scanf("%d%d",&i,&j);
m[i]=true;
a[i-1][i-1]=1;
a[i-1][j-1]=-1;
x[i-1]=0;
}
for(int i=1;i<100;i++){
if(m[i])continue;
a[i-1][i-1]=1;
x[i-1]=1;
if(i<=94){
for(int j=1;j<=6;j++)
a[i-1][i+j-1]=-1.0/6;
}else{
for(int j=1;j<=100-i;j++)
a[i-1][i+j-1]=-1.0/6;
a[i-1][i-1]-=1.0/6*(6+i-100);
}
}
a[99][99]=1;x[99]=0;Gauss();
printf("Case %d: %.10lf\n",++iCase,x[0]);
}
return 0;
}