luogu P3232 [HNOI2013]游走

https://www.luogu.com.cn/problem/P3232
由于 m m m很大,所以我们先考虑经过每个点的期望次数
i n [ i ] in[i] in[i]表示 i i i点的度数, f i f_i fi表示经过 i i i点的期望次数
可得,假设和 i i i相连的点为 j ( j < n ) j(j<n) j(j<n)
f 1 = 1 + ∑ f j i n [ j ] \large f_1=1+\sum \frac{f_j}{in[j]} f1=1+in[j]fj
f i = ∑ f j i n [ j ] ( 1 < i < n ) \large f_i=\sum\frac{f_j}{in[j]}(1<i<n) fi=in[j]fj(1<i<n)
高斯消元可求
那么对于一条边,经过它的期望次数就是
f u i n [ u ] + f v i n [ v ] \large \frac{f_u}{in[u]}+\frac{f_v}{in[v]} in[u]fu+in[v]fv
于是乎排序贪心做即可
code:

#include<bits/stdc++.h>
#define N 505
using namespace std;
struct edge {
    int v, nxt;
} e[N * N << 1];
int p[N << 1], eid;
void init() {
    memset(p, -1, sizeof p);
    eid = 0;
}
void insert(int u, int v) {
    e[eid].v = v;
    e[eid].nxt = p[u];
    p[u] = eid ++;
}
double a[N][N], X[N], ans[N * N];
void guass(int n) {
    for(int i = 1; i <= n; i ++) {
        int j = i;
        for(int k = i + 1; k <= n; k ++) if(fabs(a[k][i]) > fabs(a[j][i])) j = k;
        if(i != j) swap(a[i], a[j]);
        for(int k = i + 1; k <= n; k ++) {
            double t = a[k][i] / a[i][i];
            for(int j = i; j <= n + 1; j ++) a[k][j] -= t * a[i][j];
        }
    }
    for(int i = n; i ; i --) {
        for(int j = i + 1; j <= n; j ++) a[i][n + 1] -= a[i][j] * X[j];
        X[i] = a[i][n + 1] / a[i][i];
    }
}
int n, m, U[N * N], V[N * N], in[N];
int main() { init();
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++) {
        int u, v;
        scanf("%d%d", &u, &v); U[i] = u, V[i] = v;
        in[u] ++, in[v] ++;
        insert(u, v), insert(v, u);
    }
    for(int u = 1; u < n; u ++) {
        a[u][u] = 1.0;
        for(int i = p[u]; i + 1; i = e[i].nxt) {
            int v = e[i].v;
            if(v == n) continue;
            a[u][v] = - 1.0 / in[v];
        }
    }
    a[1][n] = 1.0;
//    for(int i = 1; i <= n; i ++) {
//        for(int j = 1; j <= n; j ++) printf("%.3lf ", a[i][j]); printf("\n");
//    }
    guass(n - 1);
   // for(int i = 1; i <= n; i ++) printf("%.3lf ", X[i]); printf("\n");
    for(int i = 1; i <= m; i ++) {
        int u = U[i], v = V[i];
        if(u != n) ans[i] += X[u] / in[u];
        if(v != n) ans[i] += X[v] / in[v];
    }
    sort(ans + 1, ans + 1 + m);
    double anss = 0;
    for(int i = 1; i <= m; i ++) anss += ans[i] * (double)(m - i + 1);
    printf("%.3lf", anss);
    return 0;
}
posted @ 2021-07-16 15:33  lahlah  阅读(39)  评论(0编辑  收藏  举报