LightOJ 1151 Snakes and Ladders 概率DP+高斯消元法

Snakes and Ladders LightOJ - 1151

从第 11 个格子走到第 100100 个格子,每次走的步数由扔筛子决定,假如超过 100100 就重新扔。其中有些格子可以跳到另外一些格子。问走到第 100100 个格子需要扔筛子次数的期望是多少?

dp[i]dp[i] 来表示第 ii 个格子的期望数,则有三种情况:

(1)第 ii 个格子不发生跳转,且扔筛子不会越界:

dp[i]=1+16j=16dp[i+j] dp[i]=1+\frac{1}{6}\sum_{j=1}^{6}dp[i+j]

(2)第 ii 个格子不发生跳转,但是扔筛子会越界:

dp[i]=1+16[j=1100idp[i+j]+j=16+i100dp[i]] dp[i]=1+\frac{1}{6}[\sum_{j=1}^{100-i}dp[i+j]+\sum_{j=1}^{6+i-100}dp[i]]

(3)第 ii 个格子发生跳转,跳转到 kk

dp[i]=dp[k] dp[i]=dp[k]

可以列出有 100100 个方程,100100 个变量的方程组,用高斯消元法进行求解。

代码如下(高斯消元法的模板改自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;
}

在这里插入图片描述

posted @ 2020-03-25 08:21  winechord  阅读(95)  评论(0编辑  收藏  举报