[HNOI2013]游走题解

题目链接

题意

给你一个\(n\)个点\(m\)条边的无向连通图从 1 号点出发,每次随机选择当前顶点的某条边走到下一个点,并获得这条边的分数,分数为这条边的编号,一旦到了\(n\)号点就结束游走,总分为获得分数的总和。安排每条边的编号,使总分的期望值最小,并输出最小的期望值

题解

看完题目能够发现,我们只要求出经过每一条边的期望,再把小的编号安排到期望值大的边上,把大的编号安排到期望值小的边上,就可以使总分的期望值最小

分析一波,发现边的期望值并不好求,但是可以先求出点的期望值

显然,每个点的期望是由相连的点的期望决定的。设\(f[x]\)为点\(x\)的期望, \(du[x]\)为点\(x\)的度数,点\(x1,x2,x3....xk\)与点\(x\)相邻,则\(f[x]= \sum_{i=1}^k \frac {f[x_i]}{du[x_i]}\)

这样,点的期望值就转化为了一个方程组,这个时候就要用到我们的高斯消元了,不过要注意的是,因为到了点\(n\)就会停止游走,所以点\(n\)的期望是不用管的。还有,因为起点为1号点,所以点1的实际期望为原期望+1

接下来要做的就是把点的期望转化为边的期望,每条边的期望都由其连接的两个端点决定,最后排个序,安排一下编号即可

最后上代码

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
double a[503][503], b[503], f[503], chu, ff[1000000], sum, du[503];
int n, m, max1, x, y, bian[1000000], bian1[1000000];
vector<int> l[503];
signed main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        scanf("%d%d", &x, &y);
        l[x].push_back(y), l[y].push_back(x), du[x]++, du[y]++, bian[i] = x, bian1[i] = y;
    }
    b[1] = 1;
    for (int i = 1; i < n; i++) {
        a[i][i] = 1.0;
        for (int j = 0; j < l[i].size(); j++)
            if (l[i][j] != n)
                a[i][l[i][j]] += -1.0 / (double)du[l[i][j]];
    }
    for (int i = 1; i < n; i++) {
        max1 = i;
        for (int j = i + 1; j < n; j++)
            if (a[j][i] > a[max1][i])
                max1 = j;
        if (i != max1)
            swap(a[i], a[max1]), swap(b[i], b[max1]);
        for (int j = i + 1; j < n; j++) {
            chu = a[j][i] / a[i][i], b[j] -= b[i] * chu;
            for (int k = i; k < n; k++) a[j][k] -= a[i][k] * chu;
        }
    }
    for (int i = n - 1; i >= 1; i--) {
        f[i] = b[i] / a[i][i];
        for (int j = 1; j < i; j++) b[j] -= a[j][i] * f[i];
    }
    for (int i = 1; i <= m; i++)
        ff[i] = f[bian[i]] / (double)du[bian[i]] + f[bian1[i]] / (double)du[bian1[i]];
    sort(ff + 1, ff + m + 1);
    for (int i = 1; i <= m; i++) sum += ff[i] * (double)(m - i + 1);
    printf("%.3lf", sum);
    return 0;
}
全部评论

相关推荐

最近群里有很多同学找我看简历,问问题,主要就是集中在明年三月份的暑期,我暑期还能进大厂嘛?我接下来该怎么做?对于我来说,我对于双非找实习的一个暴论就是title永远大于业务,你在大厂随随便便做点慢SQL治理加个索引,可能就能影响几千人,在小厂你从零到一搭建的系统可能只有几十个人在使用,量级是不一样的。对双非来说,最难的就是约面,怎么才能被大厂约面试?首先这需要一点运气,另外你也需要好的实习带给你的背书。有很多双非的同学在一些外包小厂待了四五个月,这样的产出有什么用呢?工厂的可视化大屏业务很广泛?产出无疑是重要的,但是得当你的实习公司到了一定的档次之后,比如你想走后端,那么中厂后端和大厂测开的选择,你可以选择中厂后端(注意,这里的中厂也得是一些人都知道的,比如哈啰,得物,b站之类,不是说人数超过500就叫中厂),只有这个时候你再去好好关注你的产出,要不就无脑大厂就完了。很多双非同学的误区就在这里,找到一份实习之后,就认为自己达到了阶段性的任务,根本不再投递简历,也不再提升自己,玩了几个月之后,美其名曰沉淀产出,真正的好产出能有多少呢?而实际上双非同学的第一份实习大部分都是工厂外包和政府外包!根本无产出可写😡😡😡!到了最后才发现晚了,所以对双非同学来说,不要放过任何一个从小到中,从中到大的机会,你得先有好的平台与title之后再考虑你的产出!因为那样你才将将能过了HR初筛!我认识一个双非同学,从浪潮到海康,每一段都呆不久,因为他在不断的投递和提升自己,最后去了美团,这才是双非应该做的,而我相信大部分的双非同学,在找到浪潮的那一刻就再也不会看八股,写算法,也不会打开ssob了,这才是你跟别人的差距。
迷茫的大四🐶:我也这样认为,title永远第一,只有名气大,才有人愿意了解你的简历
双非本科求职如何逆袭
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务