【LOJ #2136】「ZJOI2015」地震后的幻想乡(状压DP)
考虑对于一个边集
如果刚好加入第条边的时候联通
那么贡献就是
表示中的边恰好是最小的条的概率
设表示点集联通,连了条边的方案数
为不连通的方案数
那么有为中边数
可以枚举标号最小的点所在的连通块
那么条边恰好联通的概率就是
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=12,M=55,S=(1<<10)|5;
int n,sta,m,E[S];
ll f[S][M],g[S][M],c[M][M];
pii e[M];
inline int calc(int s){
int cnt=0;
for(int i=1;i<=m;i++)
if((s&(1<<(e[i].fi-1)))&&(s&(1<<(e[i].se-1))))cnt++;
return cnt;
}
inline int lowbit(int x){return x&(-x);}
int main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
n=read(),m=read(),sta=1<<n;
for(int i=0;i<=m;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 i=1;i<=m;i++){
e[i].fi=read(),e[i].se=read();
}
for(int i=0;i<sta;i++)E[i]=calc(i);
for(int s=1;s<sta;s++){
int now=s-lowbit(s);
for(int i=0;i<=E[s];i++){
for(int sub=now;;sub=(sub-1)&now){
int in=s-sub;
for(int j=0;j<=E[in]&&j<=i;j++){
g[s][i]+=f[in][j]*c[E[s-in]][i-j];
}
if(!sub)break;
}
f[s][i]=c[E[s]][i]-g[s][i];
}
}
double res=0;
for(int i=1;i<=m;i++){
res+=1.0*i/(m+1)*(1.0*g[sta-1][i-1]/c[m][i-1]-1.0*g[sta-1][i]/c[m][i]);
}
printf("%.6lf",res);
}