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; }