题意
题解
设 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 4 ) O(N^4) O(N4),显然难以胜任。
上述系数即对应边被经过次数的数学期望。那么可以如下定义, X i X_i Xi 代表节点 i i i 被经过次数的数学期望。枚举前驱节点,得到
X i = [ i = 1 ] + ∑ j ≠ N − 1 , e ( i , j ) ∈ G ( X j / d e g j ) X_i=[i=1]+\sum\limits_{j\neq N-1,e(i,j)\in G}(X_j/deg_j) Xi=[i=1]+j=N−1,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;
}