zoukankan      html  css  js  c++  java
  • LightOJ 1151

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

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

    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
    ", ++cnt, x[1]);
        }
        return 0;
    }
    
  • 相关阅读:
    像草一样,朝海生长
    那一次,我们属于彼此
    discuz !NT 3.5 论坛整合 .net 网站用户登录,退出
    oracel 10g 网络服务管理: 主机登录
    断章
    屏蔽浏览器左下角的js错误提示
    IE下载的文件自动加上中括号的Bug解决方案
    oracle下重置用户的所有序列
    循环追加表空间的数据文件的存储过程
    查询所有连接到ORACLE服务器的客户端IP地址的方法
  • 原文地址:https://www.cnblogs.com/Yumesenya/p/6131505.html
Copyright © 2011-2022 走看看