题目大意:
给出N,M,E,S,D四个变量,以及每次走i步的概率P[i] (1<=i<=M) 且每次有D作为初始方向。 人从起点S出发判断走到E的步数期望,且每次走到端点会沿相反方向走:N=4 S=1 D=0 : 123210
1.判断 S==E 是否成立 -->成立则输出0.00, continue;
2.判断S出发是否最终能到达E(这里可采用bfs)–>不能则输出"Impoosible !"
为方便处理走到数轴终点折返的情况我们可设立数组:
如N=4时 使n=2*N-2;0123 变成 012345 (即 012321) 终点为e和n-e;
当D=0 可bfs(s) 当D=1 则bfs(n-s)
3.由题意可推出走到E的步数期望方程:dp[i]=∑(dp[i+k]+k)*p[i] (1<=k<=M)
<解释>dp[i+k]为点 (i+k)%n 走到 E 的步数期望 而 i 走到 E 则会经历 i 走到 (i+k)%n 再到 E 这一可能,且概率为 p[i]
dp[i]=∑(dp[i+k]+k)*p[k] --> dp[i] - ∑dp[i+k]p[k] = ∑kp[k]
–>E[i] - E[(i+1)%m]*p[1] - … - E[(i+m)%m]p[m] = ∑kp[k]
由步数期望方程形式可联想到解矩阵–高斯消元法
4.高斯消元 – 板子
const int maxn = 100;
int equ, var; //equ-->方程数 var-->未知量数
bool Gauss(double A[][maxn]) { //构建增广矩阵后以A[i][vol+1]存放常数向量
for (int row = 1, col = 1; row <= equ && col <= var; ++row, ++col) {
int max_r = row;
for (int i = row + 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 (max_r != row) {
for (int i = col; i <= var; ++i) swap(A[max_r][i], A[row][i]);
swap(A[max_r][var + 1], A[row][var + 1]); //swap(E[max_r],E[row])
}
for (int i = row + 1; i <= equ; ++i) {
double tmp = A[i][col] / A[row][col];
for (int j = col; j <= var; ++j) A[i][j] -= A[row][j] * tmp;
A[i][var + 1] -= A[row][var + 1] * tmp; //E[i]-=E[row]*tmp;
}
}
for (int i = equ; i >= 1; --i) {
for (int j = i + 1; j <= var; ++j) A[i][var + 1] -= A[i][j] * A[j][var + 1];
A[i][var + 1] /= A[i][i];
}
/*for (int i = 1; i <= equ; ++i) {
for (int j = 1; j <= var + 1; ++j) cout << A[i][j] << " ";
cout << "\n";
}*/
return 1;
}
总代码如下
#pragma warning (disable :4996)
#include <bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const double PI = cos(-1.0);
const double eps = 1e-12;
#define For(i,n,m) for(int i=n;i<=m;++i)
int n, m, e, s, D, t;
int tot, equ, var;
int num[220];
double p[220], a[220][220], E[220];
const int maxn = 220;
//int equ, var; //equ-->方程数 var-->未知量数
bool Gauss(double A[][maxn]) { //构建增广矩阵后以A[i][vol+1]存放常数向量
for (int row = 1, col = 1; row <= equ && col <= var; ++row, ++col) {
int max_r = row;
for (int i = row + 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 (max_r != row) {
for (int i = col; i <= var; ++i) swap(A[max_r][i], A[row][i]);
swap(E[max_r], E[row]);
}
for (int i = row + 1; i <= equ; ++i) {
double tmp = A[i][col] / A[row][col];
for (int j = col; j <= var; ++j) A[i][j] -= A[row][j] * tmp;
E[i] -= E[row] * tmp;
}
}
for (int i = equ; i >= 1; --i) {
for (int j = i + 1; j <= var; ++j) E[i] -= a[i][j] * E[j];
E[i] /= A[i][i];
}
return 1;
}
void solve() {
memset(a, 0, sizeof(a));
memset(E, 0, sizeof(E));
for (int i = 0; i < n; ++i) {
if (num[i] == -1) continue;
if (i == e || i == n - e) { E[num[i]] = 0, a[num[i]][num[i]] = 1; continue; }
a[num[i]][num[i]] = 1;
for (int j = 1; j <= m; ++j) {
int tt = (i + j) % n;
a[num[i]][num[tt]] -= p[j];
E[num[i]] += p[j] * j;
}
}
if (Gauss(a)) cout << fixed << setprecision(2) << E[num[s]] << "\n";
else cout << "Impossible !\n";
}
void bfs(int st) {
memset(num, -1, sizeof(num));
queue<int> q;
q.push(st);
tot = 0;
num[st] = ++tot;
while (!q.empty()) {
int tmp = q.front();
q.pop();
For(i, 1, m) {
if (fabs(p[i]) < eps) continue;
int tt = (i + tmp) % n;
if (num[tt] == -1) num[tt] = ++tot, q.push(tt);
}
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
cin >> t;
while (t--) {
cin >> n >> m >> e >> s >> D;
For(i, 1, m) cin >> p[i], p[i] /= 100;
if (s == e) { cout << "0.00\n"; continue; }
n = n + n - 2;
if (D == 1) s = n - s;
bfs(s);
equ = var = tot;
if (num[e] == -1 && num[n - e] == -1) { cout << "Impossible !\n"; continue; }
solve();
}
return 0;
}