版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/87392018
题目
我们可以换个方向统计:枚举前k小的边,如果这些边使图联通并且减去第k小的边会使图不连通,那么就可以产生贡献。
那么:
其中
为前k条边使图联通且前k-1条边使图不连通。
的值就等于
这个就可以补集转化状压DP了。
AC Code:
#include<bits/stdc++.h>
#define maxn 11
#define maxm 55
using namespace std;
int n,m;
int sz[1<<maxn],lg[1<<maxn];
double C[maxm][maxm],f[maxm][1<<maxn][2];
int c[maxn][maxn];
int main()
{
scanf("%d%d",&n,&m);
C[0][0] = 1;
for(int i=1;i<maxm;i++)
{
C[i][0] = 1;
for(int j=1;j<=i;j++)
C[i][j] = C[i-1][j-1] + C[i-1][j];
}
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),u--,v--,c[u][v]=c[v][u]=1;
for(int i=0;i<n;i++) lg[1<<i] = i;
for(int i=1;i<(1<<n);i++)
{
int tmp = i & (-i) , v = lg[i & (-i)],rsta=i-tmp;
sz[i] = sz[rsta];
for(int j=0;j<n;j++)
if((rsta)>>j&1)
sz[i] += c[j][v];
}
for(int sta=1;sta<(1<<n);sta++)
{
for(int i=0;i<=sz[sta];i++)
{
int p = sta & (-sta);
for(int t=sta;t;t=(t-1)&(sta))
if((t&p) && (t!=sta))
{
for(int k=0;k<=i;k++)
f[i][sta][0] += f[k][t][1] * C[sz[sta-t]][i-k];
}
f[i][sta][1] = C[sz[sta]][i] - f[i][sta][0];
}
}
double ans = 0;
for(int i=0;i<=m;i++)
ans += f[i][(1<<n)-1][0] / C[m][i];
ans /= m+1;
printf("%.6lf\n",ans);
}