概率dp。to[i]代表第i个位置可以到的位置,初始to[i] = i。
f
[
i
]
=
{
f
[
t
o
[
i
]
]
,
t
o
[
i
]
≠
i
∑
j
=
1
6
1
6
∗
f
[
i
+
j
]
,
t
o
[
i
]
=
i
f[i]=\left\{ \begin{aligned} &f[to[i]],to[i]\neq i \\ &\sum_{j=1}^{6}\frac{1}{6} *f[i+j],to[i]=i \end{aligned} \right.
f[i]=⎩⎪⎪⎨⎪⎪⎧f[to[i]],to[i]=ij=1∑661∗f[i+j],to[i]=i
因此。对每个f[i],可列出一个方程,联立后可以对每个f[i]进行求解,求解过程可以利用高斯消元。答案即为f[1]。注意最后几个位置的转移类型可能不到6种。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
const int maxn = 1e5 + 10;
const int maxm = 1e4 + 10;
const ll mod = 1e9 + 7;
const double eps = 1e-10;
int n, to[111];
double a[110][110];
int main() {
__;
int _;
cin >> _;
for (int sce = 1; sce <= _; ++sce) {
cin >> n;
for (int i = 1; i <= 100; ++i) {
to[i] = i;
}
for (int i = 1; i <= n; ++i) {
int x, y;
cin >> x >> y;
to[x] = y;
}
memset(a, 0, sizeof a);
for (int i = 1; i <= 99; ++i) {
if (to[i] != i) {
a[i][100 + 1] = 0.0;
a[i][i] = 1.0;
a[i][to[i]] = -1.0;
continue;
}
if (i + 6 <= 100) {
for (int j = 1; j <= 6; ++j) {
a[i][i + j] += -1.0 / 6.0;
}
a[i][i] = 1.0;
} else {
for (int j = 1; j <= 100 - i; ++j) {
a[i][i + j] += -1.0 / 6.0;
}
a[i][i] = (100 - i) / 6.0;
}
a[i][101] = 1.0;
}
a[100][100] = 1.0;
for (int i = 1; i <= 100; ++i) {
int r = i;
for (int j = i + 1; j <= 100; ++j) {
if (fabs(a[j][i]) - fabs(a[r][i]) >= eps)r = j;
}
for (int j = 1; j <= 100 + 1; ++j) {
swap(a[i][j], a[r][j]);
}
for (int j = i + 1; j <= 100 + 1; ++j) {
a[i][j] /= a[i][i];
}
for (int j = 1; j <= 100; ++j) {
if (i != j) {
for (int k = i + 1; k <= 100 + 1; ++k) {
a[j][k] -= a[j][i] * a[i][k];
}
}
}
}
cout << "Case " << sce << ": ";
cout << fixed << setprecision(10) << a[1][100 + 1] << endl;
}
return 0;
}