Solution
随便状压就可以了,设f[S]为答案,g[S]为S的最大独立集点数。对于每个S,枚举其点集内每个点作为p[1],那么选了这个点之后与其相连的所有点(记作r[i])都不能选,是个递归过程。
转移有 (f_S=frac{sumlimits_{iin S}f_{S-r[i]}:: imes [g_{S-r[i]}:: +1==g_S]}{|S|})
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read(){//be careful for long long!
register int x=0,f=1;register char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
return f?x:-x;
}
const int N=21,mod=998244353;
int n,m,rel[N],f[1<<N],g[1<<N],inv[N];
int main(){
n=read(),m=read();inv[1]=1;
for(int i=2;i<=n;++i)inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod)%mod;
for(int i=1;i<=m;++i){
int u=read(),v=read();
rel[u]|=(1<<(v-1)),rel[v]|=(1<<(u-1));
}
for(int i=1;i<=n;++i)rel[i]|=(1<<(i-1));
f[0]=1;int all=(1<<n)-1;
for(int s=1;s<=all;++s){
int cnt=0;
for(int i=1;i<=n;++i)
if((s>>(i-1))&1){
++cnt;
int t=s&(all^rel[i]);
if(g[t]>=g[s])g[s]=g[t]+1,f[s]=f[t];
else if(g[t]==g[s]-1)f[s]=(f[s]+f[t])%mod;
}
f[s]=1ll*f[s]*inv[cnt]%mod;
}
printf("%d
",f[all]);
return 0;
}