状压!但是细节很多,不注意会TWAT
1.为了方便编号从0开始,所以链式前向星必须把h[i]置为-1
2.当(s&-s)>(1<<j)时,即选择的点集合中最小的一个点都比j大时,要continue!!!因为这时s&(1<<j)==0,但是它并不能累加贡献和转移!!!因为这里没考虑到疯狂WA……
3.只有s中包含j而且s的最后一个选择的点恰好是j的时候累加贡献。
4.不开long long 见祖宗
1 #include<stdio.h>
2 #define it register int
3 #define il inline
4 const int N=1000005;
5 int n,m,h[N],nxt[N],adj[N],t,u,v,lim;
6 long long ans,f[20][N];
7 il void add(){
8 nxt[++t]=h[u],h[u]=t,adj[t]=v,nxt[++t]=h[v],h[v]=t,adj[t]=u;
9 }
10 il void fr(int &num){
11 num=0;char c=getchar();int p=1;
12 while(c<'0'||c>'9') c=='-'?p=-1,c=getchar():c=getchar();
13 while(c>='0'&&c<='9') num=num*10+c-'0',c=getchar();
14 num*=p;
15 }
16 int main(){
17 fr(n),fr(m),lim=1<<n;
18 for(it i=0;i<n;++i) f[i][1<<i]=1,h[i]=-1;
19 for(it i=1;i<=m;++i) fr(u),fr(v),--u,--v,add();
20 for(it s=1;s<lim;++s)
21 for(it i=0;i<n;++i)
22 if(f[i][s])
23 for(it tp=h[i],j;~tp;tp=nxt[tp]){
24 j=adj[tp];
25 if((s&-s)>(1<<j)) continue;
26 if((s&(1<<j))) ans+=((s&-s)==(1<<j)?f[i][s]:0);
27 else f[j][s|(1<<j)]+=f[i][s];
28 }
29 printf("%lld",ans-m>>1);
30 return 0;
31 }