zoukankan      html  css  js  c++  java
  • P3232 [HNOI2013]游走

    洛谷传送门

    Solution

    看到题不要慌,不要因为是期望而慌张。像我一样

    我们一步一步分析(●'◡'●)

    首先,根据贪心的思想,期望经过次数多的边我们给它更小的编号。

    那么现在就想怎么求出每条边的期望经过次数

    经过一番思考,发现每条边只与它的两个点及点的度数有关,用式子写一下就是:

    [g_e=frac {f_u}{d_u}+frac {f_v}{d_v} ]

    (其中 (e)(langle u,v angle) 这条边, (g_e) 表示 (e) 的期望经过次数, (f_u) 表示 (u) 这个点的期望经过次数, (d_u) 表示 (u) 的度数, (f_v,d_v) 同理。)

    因为每次经过 (u) 的时候,都有 (dfrac 1{d_u}) 的概率经过这条边, (v) 同理。

    那那么我们就把问题转化到怎么求出每个点的期望经过次数

    又经过一波观察,发现每个点只和它相连的点及点的度数有关,用式子写出来就是:

    [f_u=sum_{vin E_u}frac {f_v}{d_v } ]

    (其中 (E_u) 表示和 (u) 相连的点集。)

    这个式子的道理和上面和边有关的那个式子是一样的^o^/

    但是有两个特殊的点:

    1.第 (1) 个节点是开始的节点,也就是刚开始就走过了,所以 (f_1) 的转移不一样: (f_1=1+sum frac {f_v}{d_v})

    2.第 (n) 个节点是结束的节点,也就是走到 (n) 即结束,所以任何一个点不能从 (n) 转移,计算 (g) 的时候也不能将 (dfrac {f_n}{d_n}) 计入答案。最简单的方法就是 (f_n=0)


    接下来我们可以将 (f)(n-1) 个式子看做 (n-1)(n-1) 元方程组,用高斯消元求解即可。

    注意:因为是方程组,式子的形式都是 (a_{k,1}*f_1+a_{k,2}*f_2+cdots+a_{k,i}*f_i+cdots +a_{k,n}*f_n=f_k)(a_{k,i}) 代表 (f_i) 在第 (k) 个式子中的系数),所以对于特殊的 (f_1) ,式子要变成 (sum a_{1,i}*f_i=f_1-1)

    Code

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    const int N=510,M=125010;
    const double eps=1e-9;
    int n,m,cnt,head[N],d[N],u[M],v[M];
    struct edge{
        int to,nxt;
    }e[M<<1];
    double a[N][N],g[M],ans;
    
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v){
        e[++cnt].to=v;
        e[cnt].nxt=head[u];
        head[u]=cnt;
    
        e[++cnt].to=u;
        e[cnt].nxt=head[v];
        head[v]=cnt;
    
        d[u]++; d[v]++;
    }
    
    inline void gauss(){
        for(int i=1;i<=n;i++){
            int max=i;
            for(int j=i+1;j<=n;j++) if(fabs(a[j][i])>fabs(a[max][i])) swap(max,j);
            if(max!=i)
                for(int j=1;j<=n+1;j++) swap(a[i][j],a[max][j]);
            if(fabs(a[i][i])<eps) continue;
            for(int j=1;j<=n;j++){
                if(j!=i){
                    double tmp=a[j][i]/a[i][i];
                    for(int k=i+1;k<=n+1;k++)
                        a[j][k]-=a[i][k]*tmp;
                }
            }
        }
        for(int i=1;i<=n;i++)
            a[i][n+1]/=a[i][i];
    }
    
    int main(){
        n=read(); m=read();
        for(int i=1;i<=m;i++){
            u[i]=read(); v[i]=read();
            add(u[i],v[i]);
        }
        n--; a[1][n+1]=-1.0;
        for(int u=1;u<=n;u++){
            a[u][u]=-1;
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(v!=n+1) a[u][v]=1.0/d[v];
            }
        }
        gauss();
        for(int i=1;i<=m;i++)
            g[i]=a[u[i]][n+1]/d[u[i]]+a[v[i]][n+1]/d[v[i]];
        sort(g+1,g+m+1);
        for(int i=1;i<=m;i++)
            ans+=g[i]*(m-i+1);
        printf("%.3lf
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    【leetcode】Edit Distance (hard)
    【leetcode】 Interleaving String (hard)
    【leetcode】Regular Expression Matching (hard) ★
    【leetcode】Wildcard Matching(hard) ★ 大神太牛了
    【leetcode】 Longest Valid Parentheses (hard)★
    【leetcode】 Scramble String (hard)★
    【leetcode】Maximal Rectangle (hard)★
    【leetcode】 Unique Binary Search Trees (middle)☆
    【计算机网络】应用层1
    【leetcode】Minimum Path Sum(easy)
  • 原文地址:https://www.cnblogs.com/jasony/p/14049936.html
Copyright © 2011-2022 走看看