题意: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 ", ca++, x[0]); } return 0; }