令 fS 表示点集 S 的答案, gS 表示点集 S 的连通图个数
那么 gS 可以通过枚举与编号最小的点联通的点集求出来
fS=gS−∑T∈SgT×MT,S−T , MS,T 表示把点集 S 分成几个联通块后连到 T 上的方案数
#include
#include
#include
#include
using namespace std;
const int P=1e9+7,N=1<<12;
int t,n,m;
int e[15][15],f[N],size[N],edge[N],g[N],ug[N],h[N],mer[1<<10|5][1<<10|5],pw[1010];
int G(int S){
if(~g[S]) return g[S];
int ret=pw[edge[S]],lst=S&-S; S^=lst;
for(int s=S;s;s=(s-1)&S)
ret=(ret-1LL*G(S^s^lst)*pw[edge[s]])%P;
return g[S^lst]=ret;
}
int Edge(int S,int T){
return edge[S^T]-edge[S]-edge[T];
}
int M(int S,int T){
if(!Edge(S,T)) return 0;
if(~mer[S][T]) return mer[S][T];
int ret=1LL*G(S)*Edge(S,T)%P,lst=S&-S; S^=lst;
for(int s=S;s;s=(s-1)&S){
ret=(ret+1LL*M(s,T)*G(S^s^lst)%P*Edge(S^s^lst,T))%P;
}
return mer[S^lst][T]=ret;
}
int F(int S){
if(~f[S]) return f[S];
int ret=G(S),lst=S&-S; S^=lst;
for(int s=S;s;s=(s-1)&S)
ret=(ret-1LL*F(S^s^lst)*M(s,S^s^lst))%P;
return f[S^lst]=ret;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
scanf("%d",&t);
for(int i=1;i<(1<<10);i++) size[i]=size[i>>1]+(i&1);
pw[0]=1; for(int i=1;i<=100;i++) pw[i]=2LL*pw[i-1]%P;
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) e[i][j]=1;
for(int i=1,x,y;i<=m;i++)
scanf("%d%d",&x,&y),e[x][y]=e[y][x]=0;
memset(mer,-1,sizeof(mer));
for(int i=0;i<(1<1;
for(int S=1;S<(1<if(size[S]==1) continue;
edge[S]=0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(i!=j && (S>>(i-1)&1) && (S>>(j-1)&1))
edge[S]+=e[i][j];
}
int cur=F(5);
printf("%d\n",(P+F((1<1))%P);
}
return 0;
}