AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 2214. [HNOI2013] 游走    原题链接    中等

作者: 作者的头像   Conan15 ,  2025-05-10 14:24:22 · 福建 ,  所有人可见 ,  阅读 36


2


1

一条边的贡献等于它的期望经过次数乘上它的边权。
而且一条边的贡献只和它的两个端点有关,由于 $m \leq 125000$ 所以显然不能直接对边硬维护。
转化成点:求每个点期望经过次数,记为 $f_i$。
则对于一条边 $(u,v), u \not= n$,有 $f_u = \sum\limits_{v} \frac{f_v}{deg_u}$,特殊地 $f_1$ 要加 $1$ 因为它是起点。
这东西显然可以高斯消元解决掉。
接着考虑一条边 $u,v$ 的期望经过次数:也就是先到达 $u$ 再经过或先到达 $v$ 再经过,即 $\frac{f_u}{deg_u} + \frac{f_v}{deg_v}$。
接着分配编号贪心即可,按照期望经过次数从大到小分配从小到大的编号。

#include <bits/stdc++.h>
using namespace std;
const int N = 505, M = 25e4 + 5;
int n, m, deg[N], h[N], e[M], ne[M], idx = 0;
struct Edge { int u, v; double w; } edge[M]; int tot = 0;

inline void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; }
inline void addedge(int a, int b) { deg[a]++, deg[b]++, add(a, b), add(b, a), edge[++tot] = {a, b, 0}; }

double a[N][N], f[N], ans;


void gauss() {
    for (int i = 1; i <= n; i++) {
        int t = i;
        for (int j = i + 1; j <= n; j++)
            if (a[j][i] > a[t][i]) t = j;
        for (int j = 1; j <= n + 1; j++) swap(a[t][j], a[i][j]);
        for (int j = n + 1; j >= i; j--) a[i][j] /= a[i][i];
        for (int j = i + 1; j <= n; j++) {
            double p = a[j][i];
            for (int k = i; k <= n + 1; k++) a[j][k] -= p * a[i][k];
        }
    }
    for (int i = n; i >= 1; i--)
        for (int j = i + 1; j <= n; j++) a[i][n + 1] -= a[i][j] * a[j][n + 1], a[i][j] = 0;
    for (int i = 1; i <= n; i++) f[i] = a[i][n + 1]; f[n] = 0;
}

bool cmp(Edge a, Edge b) { return a.w > b.w; }

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) h[i] = -1;
    for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), addedge(u, v);
    for (int u = 1; u <= n; u++) {
        a[u][u] = -1, a[u][n + 1] = -(u == 1);
        if (u == n) break;
        for (int i = h[u]; ~i; i = ne[i]) a[ e[i] ][u] = 1.00 / deg[u];
    }
    gauss();
    for (int i = 1; i <= m; i++) {
        int u = edge[i].u, v = edge[i].v;
        edge[i].w = f[u] / deg[u] + f[v] / deg[v];
    }
    sort(edge + 1, edge + 1 + m, cmp);
    for (int i = 1; i <= m; i++) ans += i * edge[i].w;
    printf("%.3lf\n", ans);
    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息