LightOJ 1151 Snakes and Ladders(期望DP+高斯消元)

题目链接
题意

求从1到100的期望次数,每次投一个1-6的色子走其显示步数,如果目标点超过100,这次操作不执行。
1到100之间存在单向的隧道可瞬移,需要恰好踩上去才可以

思路

由于存在环路,无法线性递推,需要构造一个方程组求解

对于存在可以瞬移的点a到b
d p [ a ] − d p [ b ] = 0 dp[a] - dp[b] = 0 dp[a]dp[b]=0


对于不会空过和传送的点a

d p [ a ] = d p [ a + 1 ] + d p [ a + 2 ] + d p [ a + 3 ] + d p [ a + 4 ] + d p [ a + 5 ] + d p [ a + 6 ] 6 + 1 dp[a] = \frac{dp[a+1] + dp[a+2] + dp[a+3] + dp[a+4] + dp[a+5] + dp[a+6]}{6}+1 dp[a]=6dp[a+1]+dp[a+2]+dp[a+3]+dp[a+4]+dp[a+5]+dp[a+6]+1
6 ∗ d p [ a ] − d p [ a + 1 ] − d p [ a + 2 ] − d p [ a + 3 ] − d p [ a + 4 ] − d p [ a + 5 ] − d p [ a + 6 ] = 6 6*dp[a] - dp[a+1] - dp[a+2] - dp[a+3] - dp[a+4] - dp[a+5] - dp[a+6] = 6 6dp[a]dp[a+1]dp[a+2]dp[a+3]dp[a+4]dp[a+5]dp[a+6]=6


对于目标点可能超过100的点,如96点的期望。

d p [ 96 ] = d p [ 97 ] + d p [ 98 ] + d p [ 99 ] + d p [ 100 ] + d p [ 96 ] + d p [ 96 ] 6 + 1 dp[96] = \frac{dp[97]+dp[98]+dp[99]+dp[100]+dp[96]+dp[96]} {6}+1 dp[96]=6dp[97]+dp[98]+dp[99]+dp[100]+dp[96]+dp[96]+1
4 ∗ d p [ 96 ] − d p [ 97 ] − d p [ 98 ] − d p [ 99 ] − d p [ 100 ] = 6 4*dp[96]-dp[97]-dp[98]-dp[99]-dp[100] = 6 4dp[96]dp[97]dp[98]dp[99]dp[100]=6


还有终点 d p [ 100 ] = 0 dp[100] = 0 dp[100]=0

构造完矩阵高斯消元一波求出dp[1]即为期望。

代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define eps 1e-9
const int maxn = 105;

double mat[maxn][maxn], ans[maxn];
int equ = 100, var = 100;

double abb(double fuck)
{
    return fuck < 0 ? -fuck : fuck;
}

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(abb(mat[i][col]) > abb(mat[max_r][col])) max_r = i;
        if(abb(mat[max_r][col] < eps)) return 0;
        if(k != max_r)
        {
            for(j = col; j < var; ++j) swap(mat[k][j], mat[max_r][j]);
            swap(ans[k],ans[max_r]);
        }
        ans[k] /= mat[k][col];
        for(j = col+1; j < var; ++j) mat[k][j] /= mat[k][col];
        mat[k][col] = 1;
        for(i = 0; i < equ; ++i)
        {
            if(i != k)
            {
                ans[i] -= ans[k]*mat[i][col];
                for(j = col+1; j < var; ++j) mat[i][j] -= mat[k][j] * mat[i][col];
                mat[i][col] = 0;
            }
        }
    }
    return 1;
}

int vis[105];

int main()
{
    int t, ca = 1;
    for(scanf("%d",&t); ca <= t; ++ca)
    {
        memset(mat,0,sizeof(mat));
        memset(ans,0,sizeof(ans));
        memset(vis,0,sizeof(vis));
        int m, a, b;
        scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d",&a,&b);
            vis[a-1] = 1;
            mat[a-1][a-1] = 1.0;
            mat[a-1][b-1] = -1.0;
            ans[a-1] = 0;
        }
        for(int i = 0; i < 94; ++i)
        {
            if(vis[i]) continue;
            mat[i][i] = 6;
            for(int j = 1; j < 7; ++j) mat[i][i+j] = -1;
            ans[i] = 6;
        }
        for(int i = 94; i < 99; ++i)
        {
            if(vis[i]) continue;
            mat[i][i] = 99-i;
            for(int j = i+1; j < 100; ++j) mat[i][j] = -1;
            ans[i] = 6;
        }
        mat[99][99] = 1; ans[99] = 0;
        Gauss();
        printf("Case %d: %.6lf\n",ca,ans[0]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值