zoukankan      html  css  js  c++  java
  • 【BZOJ3925】[ZJOI2015] 地震后的幻想乡(状压期望DP)

    点此看题面

    大致题意:(n)个点和(m)条边,每条边的权值是一个(0sim1)的随机实数,要你用(n-1)条边将图联通,问这(n-1)条边中边权最大值的期望最小值。

    提示

    这题应该是一道比较难的(DP)题吧。

    首先,我们需要注意到提示中的一句话:

    (Hint)

    对于(n)([0,1])之间的随机变量(x_1,x_2,...,x_n),第(k)小的那个的期望值是(frac k{n+1})

    其实,这就很明显在提示我们,只要求出这(n-1)条边中权值最大边的期望最小排名,我们就能轻松求出它的期望最小值

    于是我们就能形成一个比较基础的思路了。

    基础思路

    首先,应该不难想到,可以用(P_i)来表示权值最大边排名为(i)的概率,而答案就是(sum_{i=1}^mi·P_i)(这应该还是比较显然的)。

    但问题在于这样很难进行状态转移。

    我们可以将原式进行进一步的转化,则不难发现,答案其实就相当于(sum_{i=1}^msum_{j=i}^mP(j))

    由于(sum_{i=1}^mP(i)=1),所以上面式子中的(sum_{j=i}^mP(j))其实又等价于(1-sum_{j=1}^{i-1}P(j))

    考虑(sum_{j=1}^{i-1}P(j))表示的是加入(i-1)条边能使原图联通的概率,所以(1-sum_{j=1}^{i-1}P(j))其实就相当于加入(i-1)条边不能使原图联通的概率

    不难发现,这比求原式要容易多了。

    转化后的问题

    整理一下上面的思路,就可以得到一个这样的问题:设(P'(i))为加入(i)条边后原图不连通的概率,求(sum_{i=0}^{m-1}P'(i))

    注意到(nle10)这极小的范围,我们首先想到的自然是乱搞状压(DP)

    状压(DP)

    考虑用(f_{i,t,0/1})来表示连接(i)条边后使点集(j)不连通/联通的方案数,注意,这里记录的是方案数而不是概率,这样可以防止出现精度误差(毕竟要保留(6)位小数)。

    我们可以用(Size_i)(line\_tot_i)分别表示点集(i)点与边的数量

    首先,我们要知道一个比较基础的知识,即在点集(i)中选择(t)条边的方案数应为(C_{line\_tot_i}^t),即(f_{i,t,0}+f_{i,t,1}=C_{line\_tot_i}^t)

    既然这样,只要求出(f_{i,t,0})(f_{i,t,1})中的一个,我们就可以轻松求出另一个的值了。

    比较显然(f_{i,t,0})相对而言要更容易求一些。

    状态转移

    我们来考虑如何进行状态转移。

    考虑在当前点集中任意选取一点(k)作为定点((k)取什么点无所谓,为了方便推荐选择(lowbit(i)),可以(O(1))求出),然后枚举含有点(k)的点集(j),进行转移。

    不难想到,如果要让点集(j)变成(i),自然需要加入(i)^(j)这个点集。

    我们可以在保证点集(j)联通的情况下,枚举(x,y(0le xle line\_tot_j,0le yle line\_tot_{i ext{^}j})),表示两个点集中的分别选择的边数。

    由于选(x)条边使点集(j)联通的方案数为(f_{j,x,1}),而(y)条边的选择方案数共有(C_{line\_tot_{i ext{^}j}}^y),所以可以得出转移方程:

    [f_{i,x+y,0}=sum f_{j,x,1}*C_{line\_tot_{i ext{^}j}}^y ]

    这样就可以不重不漏地统计到所有情况了。

    最后的答案

    根据一开始得出的结论,最后的答案就是:

    [frac{sum_{i=0}^{m-1}frac{f_{2^n-1,i,0}}{C_m^i}}{m+1} ]

    还有,千万注意精度啊。

    一些细节:关于(Size)(line\_tot)数组的求法

    关于(Size)(line\_tot)两个数组,其实有一种比较巧妙的求法。(会的大佬可以直接跳过这一部分)

    • (Size_i=Size_{i>>1}+(i&1))
      • 首先,由于((i>>1)<i),所以(Size_{i>>1})一定在求(Size_i)之前已经求解过。
      • 其次,由于((i>>1))(i)在二进制下只相差最后一位,所以只要比较最后一位(即(i&1))就可以求出结果。
    • (line\_tot_i=frac{sum Size_{Next_j&i}}2)
      • 注意,上面式子中的(j)表示点集(i)中的一个点,而(Next_j)表示与(j)有边相连的点的点集。
      • 首先,由于(Next_j&ile i),所以(Size_{Next_j&i})肯定已经求解过。
      • 其次,将与(j)相连的点与点集(i)中的点(&)一下,得到的结果就是点集(i)中与(j)相连的点的点集,它的(Size)就是点集(i)中与(j)有边相连的点的数量,即以点(j)为一个端点的边数。
      • 但这样会把每条边统计两次,因此最后除以(2)即可。

    代码

    #include<bits/stdc++.h>
    #define N 10
    #define M 50
    #define LL long long
    using namespace std;
    int n,m,Next[N+5],line_tot[1<<N+1],Size[1<<N+1];LL f[1<<N+1][M+5][2],C[M+5][M+5];
    class Class_FIO
    {
        private:
            #define Fsize 100000
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
            char ch,*A,*B,Fin[Fsize];
        public:
            Class_FIO() {A=B=Fin;}
            inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
    }F;
    inline void Init() {for(register int i=C[0][0]=1,j;i<=M;++i) for(C[i][0]=C[i][i]=j=1;j<i;++j) C[i][j]=C[i-1][j-1]+C[i-1][j];}//预处理组合数
    int main()
    {
        register int i,j,k,x,y,Full;register double ans=0.0;
        for(Init(),F.read(n),F.read(m),i=1;i<=m;++i) F.read(x),F.read(y),Next[x]|=(1<<y-1),Next[y]|=(1<<x-1);//用Next[i]存储与i有边相连的点的点集
        for(i=1,Full=(1<<n)-1;i<=Full;++i)//枚举每一个点集i
        {
            if((Size[i]=Size[i>>1]+(i&1))==1) {f[i][0][1]=1;continue;}//如果只有一个点,跳过
            for(j=1;j<=n;++j) if(i&(1<<j-1)) line_tot[i]+=Size[Next[j]&i];line_tot[i]>>=1;//统计边数
            for(k=i&-i,j=i&(i-1);j;j=i&(j-1)) if(j&k) for(x=0;x<=line_tot[j];++x) for(y=0;y<=line_tot[i^j];++y) f[i][x+y][0]+=f[j][x][1]*C[line_tot[i^j]][y];//状态转移
            for(j=0;j<=line_tot[i];++j) f[i][j][1]=C[line_tot[i]][j]-f[i][j][0];//根据f[i][j][0]得到f[i][j][1]的值
        }
        for(i=0;i<=m;++i) ans+=1.0*f[Full][i][0]/C[line_tot[Full]][i];ans/=m+1;//统计答案
        return printf("%.6lf",ans),0;
    }
    
  • 相关阅读:
    matplotlib 进阶之origin and extent in imshow
    Momentum and NAG
    matplotlib 进阶之Tight Layout guide
    matplotlib 进阶之Constrained Layout Guide
    matplotlib 进阶之Customizing Figure Layouts Using GridSpec and Other Functions
    matplotlb 进阶之Styling with cycler
    matplotlib 进阶之Legend guide
    Django Admin Cookbook-10如何启用对计算字段的过滤
    Django Admin Cookbook-9如何启用对计算字段的排序
    Django Admin Cookbook-8如何在Django admin中优化查询
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3925.html
Copyright © 2011-2022 走看看