【高斯消元求期望】LightOJ
阿新 • • 發佈:2018-12-24
Step1 Problem:
有 100 個格子,從 1 開始走,每次拋骰子走 1~6,如果所走位置大於 100,則重新拋骰子。i 會被傳送至 nex[i]。
問你從 1 走到 100 所拋骰子的期望次數。
Step2 Ideas:
由期望公式可得:.
由上述式子可以看出,得先求出後續狀態才能推出 dp[i],所以當後續狀態由前面狀態推出來的時候也就是 i 會被傳送至 nex[i],就很明顯的需要列方程了。
第二個方程:.
然後高斯消元解方程即可。
Step3 Code:
#include<bits/stdc++.h> using namespace std; const int N = 110; double data[N][N]; double ans[N]; double eps = 1e-8; int lib[N], nex[N], n; bool eq(double x, double y) { if(fabs(x-y) <= eps) return 1; else return 0; } int Gauss() { int rst = 0, r = 0; memset(lib, 0, sizeof(lib)); for(int i = 0; i < n; i++) { for(int j = r; j < n; j++) { if(eq(data[j][i], 0)) continue; for(int k = 0; k <= n; k++) swap(data[j][k], data[r][k]); break; } if(eq(data[r][i], 0)) continue; for(int j = 0; j < n; j++)//利用r消去其他行,和01矩陣不同的地方 { if(j == r || eq(data[j][i], 0)) continue; double t = data[r][i]/data[j][i]; for(int k = 0; k <= n; k++) data[j][k] = data[j][k]*t - data[r][k]; } lib[i] = 1; r++; rst++; } for(int i = 0; i < n; i++) { if(eq(data[i][n], 0) == 0) { int flag = 0; for(int j = 0; j < n; j++) { if(eq(data[i][j], 0) == 0) { flag = 1; break; } } if(!flag) { return -1; } } if(!lib[i]) continue; if(eq(data[i][i], 0)) continue; ans[i] = data[i][n] / data[i][i]; } return rst; } int main() { int T, m, u, v; scanf("%d", &T); for(int Case = 1; Case <= T; Case++) { scanf("%d", &m); n = 100; memset(nex, -1, sizeof(nex)); for(int i = 1; i <= m; i++) { scanf("%d %d", &u, &v); nex[u-1] = v-1; } memset(data, 0, sizeof(data)); // 100個解,需要100個方程組 data[n-1][n-1] = 1, data[n-1][n] = 0;//你在 100 這個格子,期望步數就是 0 了. for(int i = 0; i < n-1; i++) { if(nex[i] != -1) { data[i][i] = 1; data[i][nex[i]] = -1; data[i][n] = 0; } else { int cnt = 0; for(int j = 1; j <= 6; j++) { if(i+j < n) { data[i][i+j] = -1; cnt++; } } data[i][i] = cnt; data[i][n] = 6; } } Gauss(); printf("Case %d: %lf\n", Case, ans[0]); } return 0; }