- 首先考了选择前 \(k\) 小的边,恰好使得联通的概率 \(p_k\)
- 此时的期望边权为 \(\frac{k}{m+1}\),其实就是第 \(k\) 小
- \(p_k=\frac{g_k}{\binom{m}{k}}\),至于 \(g_k\) 怎么求
- 可以考虑 \(g_{s,i}\),其中 \(s\) 为点集的状压的值,表示 \(i\) 个边使得点集 \(s\) 里的点联通的方案数
- \(f_{s,i}\) 表示点集 \(s\) 不联通的方案数,\(h_s\) 表示原图上点集 \(s\) 两两连边的边数
- \(g_{s,i}=\binom{h_s}{i}-f_{s,i}\)
- \(f_{s,i}=\sum_{k\in t\subsetneqq s}g_{t,j}\binom{h_{s-t}}{i-j}\),\(k\) 是我们钦定的一个数在 \(s\) 中的一个点,枚举它所在的联通块,其他的随便选即可
- 恰好联通不好计算,但是其等价于,没删这条边之前联通 减 删后不联通的方案数
- \(Ans=\sum p_k\frac{k}{m+1}=\sum(\frac{f_{u,k-1}}{\binom{m}{k-1}}-\frac{f_{u,k}}{\binom{m}{k}})\frac{k}{(m+1)}=\frac{1}{m+1}\sum_{k=1}^m\frac{f_{u,k}}{\binom{h_{u}}{k}}\),其中 \(u\) 为全集
#include <bits/stdc++.h>
using namespace std;
inline int id(int x){x--;return 1<<x;}template<class ...T>inline int id(int x,T...t){return id(x)|id(t...);}
const int N=10,M=1<<N,K=51;
int n,m,cnt[M],sum[M]; double f[M][K],g[M][K],c[K][K];
int main()
{
cin>>n>>m; int u,v,nn=1<<n;
for(int i=1;i<=m;i++)
cin>>u>>v,cnt[id(u,v)]++;
for(int s=0;s<nn;s++)
for(int t=s;t;t=s&t-1)
sum[s]+=cnt[t];
c[0][0]=1;
for(int i=1;i<K;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
for(int s=1;s<nn;s++)for(int i=0;i<=sum[s];i++)
{
for(int t=s;t;t=s&t-1)for(int j=0;j<=min(i,sum[s-t]);j++)
if((s-t)&(s&-s))f[s][i]+=g[s-t][j]*c[sum[t]][i-j];
g[s][i]=c[sum[s]][i]-f[s][i];
}
double ans=0;
for(int i=0;i<=m;i++)ans+=f[nn-1][i]/c[m][i];
ans/=m+1;printf("%.6lf\n",ans);
return 0;
}