题意
题解
设 X i X_i Xi 为 i → N i\rightarrow N i→N 的期望分数。考虑一步转移状态可以列出 N N N 个 N N N 元一次方程。若能通过高斯消元将 X 1 X_1 X1 用边编号的线性组合表示,那么就能够基于贪心策略,将编号的系数排序,较小的编号对应较大的系数,从而得到答案。总时间复杂度 O ( N 6 ) O(N^6) O(N6),显然难以胜任。
上述系数即对应边被经过次数的数学期望。那么可以如下定义,
X
i
X_i
Xi 代表节点
i
i
i 被经过次数的数学期望。枚举前驱节点,得到
X
i
=
[
i
=
1
]
+
∑
j
≠
N
,
e
(
i
,
j
)
∈
G
(
X
j
/
d
e
g
j
)
X_i=[i=1]+\sum\limits_{j\neq N,e(i,j)\in G}(X_j/deg_j)
Xi=[i=1]+j=N,e(i,j)∈G∑(Xj/degj) 对任一条边
(
i
,
j
)
(i,j)
(i,j),非
N
N
N 的端点
i
i
i 对边的贡献为
X
i
/
d
e
g
i
X_i/deg_i
Xi/degi。那么得到
N
−
1
N-1
N−1 个
N
−
1
N-1
N−1 元一次方程,高斯消元求解即可。总时间复杂度
O
(
N
3
)
O(N^3)
O(N3)。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
typedef double db;
const int maxn = 505;
int N, M, deg[maxn], G[maxn][maxn];
db A[maxn][maxn], X[maxn], Y[maxn], F[maxn * maxn];
void gauss_jordan(db A[][maxn], int n)
{
rep(i, 0, n)
{
int pivot = i;
rep(j, i + 1, n) if (abs(A[pivot][i]) < abs(A[j][i])) swap(pivot, j);
rep(j, 0, n + 1) swap(A[pivot][j], A[i][j]);
rep(j, i + 1, n + 1) A[i][j] /= A[i][i];
rep(j, 0, n) if (j != i)
{
db t = A[j][i];
rep(k, i + 1, n + 1) A[j][k] -= t * A[i][k];
}
}
rep(i, 0, n) X[i] = A[i][n];
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> M;
rep(i, 0, M)
{
int u, v;
cin >> u >> v;
--u, --v;
++deg[u], ++deg[v];
G[u][v] = G[v][u] = 1;
}
rep(u, 0, N - 1)
{
rep(v, 0, N - 1) if (G[u][v])
A[u][v] = 1.0 / deg[v];
A[u][u] = -1.0;
if (u == 0)
A[u][N - 1] = -1.0;
}
gauss_jordan(A, N - 1);
rep(u, 0, N - 1) Y[u] = X[u] / deg[u];
for (int u = 0, k = 0; u < N - 1; ++u)
{
if (G[u][N - 1])
F[k++] = Y[u];
rep(v, u + 1, N - 1) if (G[u][v]) F[k++] = Y[u] + Y[v];
}
sort(F, F + M);
db res = 0;
rep(i, 0, M) res += F[i] * (M - i);
cout << fixed << setprecision(3) << res << '\n';
return 0;
}