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

首先来个期望的论文,讲的非常好,里面也提到了使用线性方程组求解,尤其适用于有向图的期望问题。

算法合集之《浅析竞赛中一类数学期望问题的解决方法》

http://www.lightoj.com/volume_showproblem.php?problem=1151

题意:有个1~100个格子的地图,每次投骰子,点数1~6,问到达第100格所需的投骰子次数期望值是多少,注意如果最后走的点数超出了地图,不算完成。地图中有传送门,a b表示从第a格可以到b格。

思路:首先可以想到DP的转移有两种,如果i是传送门那么\(dp[i] = dp[tp[i]] \),如果不是,则\(dp[i]=\frac{6+\sum_{j = 1}^{6}{dp[i+j]}}{6}\) 由于传送门可能成环,那么路径有无数条,所以需要转换成方程\(6 * dp[i] - \sum_{j = 1}^{6}{dp[i+j]} = 6 \)  ,\(dp[i] - dp[tp[i]] = 0 \)

再用高斯消元求解。

高斯消元的模板网上找的..

 

/** @Date    : 2016-12-03-20.06
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version :
  */

#include<bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+2000;
const double eps = 1e-12;

int tp[110];
double mat[110][110];
double x[110];
int free_x[110];

int Gauss(int equ, int var)
{
    int k;
    int max_r;
    int col;
    int ta, tb;
    int LCM;
    int temp;
    int free_idx, free_num;
    memset(free_x, 1, sizeof(free_x));
    MMF(x);

    for(k = col = 0; k < equ && col < var; k++, col++)
    {
        max_r = k;
        for(int i = k + 1; i < equ; i++)
            if(fabs(mat[i][col]) - fabs(mat[max_r][col]) > eps)
                max_r = i;

        if(max_r != k)
            for(int j = k; j < var + 1; j++)
                swap(mat[max_r][j], mat[k][j]);

        if(fabs(mat[k][col]) <= eps)
        {
            k--;
            continue;
        }
        for(int i = k + 1; i < equ; i++)
        {
            if(fabs(mat[i][col]) <= eps)
                continue;
            double tt = mat[i][col] / mat[k][col];
            for(int j = col; j < var + 1; j++)
                mat[i][j] -= mat[k][j] * tt;
        }
    }
    //no solution
    for(int i = k; i <= equ; i++)
        if(fabs(mat[i][var]) > eps)
            return -1;
    //multiple
    if(k < var)
    {
        for(int i = k - 1; i >= 0; i--)
        {
            free_num = 0;
            for(int j = 0; j < var; j++)
                if(fabs(mat[i][j]) > eps && free_x[j])
                {
                    free_num++;
                    free_idx = j;
                }
            if(free_num > 1)//multiple var, and can't solve
                continue;

            double tt = mat[i][var];
            for(int j = 0; j < var; j++)
                if(j != free_num && fabs(mat[i][j]) > eps)
                    tt -= mat[i][j] * x[j];

            free_x[free_idx] = 0;
            x[free_idx] = tt / mat[i][free_idx];
        }
        return var - k;
    }
    //only one
    for(int i = var - 1; i >= 0; i--)
    {
        double tt = mat[i][var];
        for(int j = i + 1; j < var; j++)
            if(fabs(mat[i][j]) > eps)
                tt -= mat[i][j] * x[j];
        x[i] = tt / mat[i][i];
    }
    return 1;
}



int main()
{
    int T;
    int cnt = 0;
    cin >> T;
    while(T--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= 100; i++)
        {
            tp[i] = i;
        }

        int a, b;
        for(int i = 1; i <= n; i++)
            scanf("%d%d", &a, &b), tp[a] = b;

        MMF(mat);
        mat[100][100] = 1;
        mat[100][101] = 0;
        for(int i = 1; i < 100; i++)
        {
            if(tp[i] != i)
            {
                mat[i][i] = 1;
                mat[i][tp[i]] = -1;
                mat[i][101] = 0;
            }
            else
            {
                int k = 0;
                for(int j = 1; j <= 6; j++)
                    if(j + i <= 100)
                    {
                        k++;
                        mat[i][i + j] = -1;
                    }
                mat[i][i] = k;
                mat[i][101] = 6;
            }
        }
        Gauss(101, 101);
        printf("Case %d: %.10lf\n", ++cnt, x[1]);
    }
    return 0;
}
posted @ 2016-12-04 19:12  Lweleth  阅读(472)  评论(0编辑  收藏  举报