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

题意:1~100的格子,有n个传送阵,一个把进入i的人瞬间传送到tp[i](可能传送到前面,也可能是后面),已知传送阵终点不会有另一个传送阵,1和100都不会有传送阵。每次走都需要掷一次骰子(1~6且可能性一样),掷多少走多少,目的地超出100重掷,问你走到100所需掷骰子的期望。

思路:概率DP肯定的,但是会往前传送就很难直接算。用DP[i]代表从i走到100的期望。

那么如果i没有传送阵,则有:DP[i] = 1 / 6 * sum(DP[i + j]) + 1,1<= j <= 6,如果超出100则有:DP[i] = 1 / 6 * sum((DP[i + j]) + DP[i] * k),k = min(100 - i,6),1<= j < k

有传送阵:DP[i] - DP[tp[i]] = 0

然后根据上式解出这个100元1次方程,用高斯消元

代码:

#include<set>
#include<map>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
typedef long long ll;
using namespace std;
const int maxn = 100 + 10;
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
double a[maxn][maxn], x[maxn];
int equ, var;
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(k != max_r){
            for(j = col; j < var; j++)
                swap(a[k][j], a[max_r][j]);
            swap(x[k], x[max_r]);
        }
        x[k] /= a[k][col];
        for(j = col + 1; j < var; j++) a[k][j] /= a[k][col];
        a[k][col] = 1;
        for(i = 0; i < equ; i++)
        if(i != k){
            x[i] -= x[k] * a[i][col];
            for(j = col + 1; j < var; j++) a[i][j] -= a[k][j] * a[i][col];
            a[i][col] = 0;
        }
    }
    return 1;
}
int tp[maxn];
int main(){
    int t, ca = 1;
    scanf("%d", &t);
    while(t--){
        equ = var = 100;
        int n;
        scanf("%d", &n);
        memset(tp, -1, sizeof(tp));
        memset(a, 0, sizeof(a));
        for(int i = 0; i < n; i++){
            int p;
            scanf("%d", &p);
            --p;
            scanf("%d", &tp[p]);
            --tp[p];
        }
        for(int i = 0; i < 100; i++){
            if(tp[i] == -1){
                int k = min(99 - i, 6);
                a[i][i] = 6;
                for(int j = i + 1; j <= i + k; j++){
                    a[i][j] = -1;
                }
                if(k < 6) a[i][i] -= 6 - k;
                x[i] = 6;
            }
            else{
                a[i][i] = 1;
                a[i][tp[i]] = -1;
                x[i] = 0;
            }
        }
        Gauss();
        printf("Case %d: %.8lf\n", ca++, x[0]);
    }
    return 0;
}

 

 

posted @ 2019-03-15 21:11  KirinSB  阅读(144)  评论(0编辑  收藏  举报