P3232 [HNOI2013] 数学期望 + 高斯消元

题意

传送门 P3232 [HNOI2013]游走

题解

X i X_i Xi i → N i\rightarrow N iN 的期望分数。考虑一步转移状态可以列出 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=N1,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 N1 N − 1 N-1 N1 元一次方程,高斯消元求解即可。总时间复杂度 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;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/120451997
今日推荐