zoukankan      html  css  js  c++  java
  • 【BZOJ3143】游走(HNOI2013)-DP+概率期望+高斯消元

    测试地址:游走
    做法:本题需要用到DP+概率期望+高斯消元。
    首先根据期望可加性,我们知道路径和的期望等于每条边的期望经过次数乘上边权。又根据排序不等式,我们知道给大的期望次数分配小的编号是最优的,那么现在问题就变成求每条边的期望经过次数。
    我们可以先求出每个点的期望经过次数pi,然后边(i,j)的期望经过次数就是pideg(i)+pjdeg(j),其中deg(i)表示点i的度数。那么对于每个点我们有状态转移方程:
    pi=(i,j)E1deg(j)pj
    把所有点的方程列出来后,O(n3)高斯消元直接把未知数求出来即可。
    这里要注意几个问题:一是因为点n是终止节点,所以它对所有其他点都不会做出贡献,直接去掉。二是点1的方程实际上是p1=1+(1,j)E1deg(j)pj,因为游走是从点1开始的,所以必定先有一次经过,然后才开始随机游走的过程。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m;
    double g[510][510]={0},deg[510]={0},p[510];
    struct edge
    {
        int a,b;
        double p;
    }e[300010];
    
    void gauss(int n)
    {
        for(int i=1;i<=n;i++)
        {
            int mx=i;
            for(int j=i;j<=n;j++)
                if (fabs(g[j][i])>fabs(g[mx][i])) mx=j;
            for(int j=i;j<=n+1;j++)
                swap(g[i][j],g[mx][j]);
            for(int j=1;j<=n;j++)
                if (j!=i)
                {
                    for(int k=i+1;k<=n+1;k++)
                        g[j][k]-=g[j][i]*g[i][k]/g[i][i];
                    g[j][i]=0.0;
                }
        }
    }
    
    bool cmp(edge a,edge b)
    {
        return a.p>b.p;
    }
    
    void init()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&e[i].a,&e[i].b);
            deg[e[i].a]++,deg[e[i].b]++;
        }
        for(int i=1;i<=m;i++)
        {
            if (e[i].b!=n) g[e[i].a][e[i].b]=-1.0/deg[e[i].b];
            if (e[i].a!=n) g[e[i].b][e[i].a]=-1.0/deg[e[i].a];
        }
        for(int i=1;i<n;i++)
            g[i][i]=1.0;
        g[1][n]=1.0; 
    }
    
    void work()
    {
        gauss(n-1);
        for(int i=1;i<n;i++)
            p[i]=g[i][n]/g[i][i];
        for(int i=1;i<=m;i++)
        {
            e[i].p=0;
            if (e[i].a!=n) e[i].p+=p[e[i].a]/deg[e[i].a];
            if (e[i].b!=n) e[i].p+=p[e[i].b]/deg[e[i].b];
        }
        sort(e+1,e+m+1,cmp);
        double ans=0.0;
        for(int i=1;i<=m;i++)
            ans+=e[i].p*(long double)i;
        printf("%.3lf",ans);
    }
    
    int main()
    {
        init();
        work();
    
        return 0;
    }
  • 相关阅读:
    洛谷 P3366 【模板】最小生成树
    洛谷 P2820 局域网
    一本通【例4-10】最优布线问题
    洛谷 P1546 最短网络 Agri-Net
    图论模板
    洛谷 AT667 【天下一人力比較】
    刷题记录
    洛谷P1553 数字翻转(升级版)
    tornado硬件管理系统-网络与磁盘的实现(7)
    tornado硬件管理系统-内存与swap的实现(6)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793482.html
Copyright © 2011-2022 走看看