[HNOI2013]游走

[HNOI2013]游走

考虑随机游走时一条边 $ (x,y) $ 被经过,只有两种情况,要么是我们走到了点 $ x $ ,然后随机钦定了 $ y $ ,要么就是反过来。我们假设一个点的度数为 $ deg[i] $ ,假设一个点期望会经过 $ t[u] $ 次,所以一个边所贡献的权值就是 $ w \times ( \frac{t[x]}{deg[x]} + \frac{t[y]}{deg[y]} ) $ 。

所以现在我们的目标就是求 $ t $ 。发现 $ n \leq 500 $ 我们可以考虑高消,具体而言,可以列出

\[t[u] = \sum \frac{t[v]}{deg[v]} \]

特别的,对于第一个点必然会被经过一次, $ t[1] = 1 + \sum \frac{t[v]}{deg[v]} $ ,而 $ t[n] = 0 $,因为到达了 $ n $ 号点就结束了。

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
using namespace std;
#define MAXN 506
int n , m;
#define eps 1e-6
int deg[MAXN];
double A[MAXN][MAXN];
int gauss(  ) {
    for( int i = 1 ; i <= n ; ++ i ) { // cur : 第 i 行
        int mxpos = i;
        for( int j = i ; j <= n ; ++ j ) if( fabs( A[j][i] ) - fabs( A[mxpos][i] ) > eps )
                mxpos = j;
        for( int j = 1 ; j <= n + 1 ; ++ j )
            swap( A[i][j] , A[mxpos][j] );
        double c = A[i][i];
        if( c == 0 ) { return 0; }
        A[i][i] = 1;
        for( int j = i + 1 ; j <= n + 1 ; ++ j )
            A[i][j] /= c;
        for( int j = 1 ; j <= n ; ++ j ) if( j != i ) { // cur : 第 j 行
                double cc = A[j][i]; A[j][i] = 0;
                for( int k = i + 1 ; k <= n + 1 ; ++ k ) // cur : 第 k 列
                    A[j][k] -= cc * A[i][k];
            }
    }
    return 1;
}
pair<int,int> E[MAXN * MAXN];
double w[MAXN * MAXN];
int G[MAXN][MAXN];
int main() {
    cin >> n >> m;
    for( int i = 1 , u , v ; i <= m ; ++ i ) {
        scanf("%d%d",&u,&v);
        ++ deg[u] , ++ deg[v]; G[u][v] = G[v][u] = 1;
        E[i] = make_pair( u , v );
    }
    A[1][n + 1] = -1;
    for( int i = 1 ; i < n ; ++ i )
        for( int j = 1 ; j < n ; ++ j )
            if( G[i][j] )
                A[i][j] = 1.0 / deg[j];
            else if( i == j ) A[i][j] = -1.0;
    A[n][n] = 1;
//    for( int i = 1 ; i <= n ; ++ i ) {
//        for (int j = 1; j <= n + 1; ++j) printf("%.3f ", A[i][j]); puts("");
//    }
    gauss( );
//    for( int i = 1 ; i <= n ; ++ i ) cout << A[i][n + 1] << endl;
    for( int i = 1 ; i <= m ; ++ i ) {
        int u = E[i].first , v = E[i].second;
        w[i] = A[u][n + 1] / deg[u] + A[v][n + 1] / deg[v];
    }
    sort( w + 1 , w + 1 + m );
    double res = 0;
    for( int i = 1 ; i <= m ; ++ i ) res += ( m - i + 1 ) * w[i];
    printf("%.3f",res);
}
posted @ 2020-02-18 12:22  yijan  阅读(142)  评论(0编辑  收藏  举报