dalao教导我们,看到计数想容斥……
卡常策略:枚举顺序、除去无效状态、(树结构)
#include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=20; LL f[N][N]; int n,m,d[N][N],full; bool yeah[N]; int st[N],cnt; struct V{ int to,next; }c[N<<1]; int head[N],t; inline void add(int x,int y){ c[++t].to=y,c[t].next=head[x],head[x]=t; } inline void dfs(int x,int fa){ register int i,j,k;LL sum=0; for(i=head[x];i;i=c[i].next) if(c[i].to!=fa) dfs(c[i].to,x); for(i=1;i<=n;++i){ if(!yeah[i]){ f[x][i]=0; continue; } f[x][i]=1; for(j=head[x];j;j=c[j].next) if(c[j].to!=fa){ sum=0; for(k=1;k<=cnt;++k) if(d[i][st[k]]) sum+=f[c[j].to][st[k]]; f[x][i]*=sum; } } } int main(){ scanf("%d%d",&n,&m); full=(1<<n)-1; int i,j,x,y; for(i=1;i<=m;++i){ scanf("%d%d",&x,&y); d[x][y]=d[y][x]=1; } for(i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y),add(y,x); } LL ans=0,sum; for(i=1;i<=full;++i){ cnt=0,sum=0; for(j=0;j<n;++j) if(i&(1<<j))yeah[j+1]=true,st[++cnt]=j+1; else yeah[j+1]=false; dfs(1,0); for(j=1;j<=n;++j) sum+=f[1][j]; ans+=(((n-cnt)&1)?-1:1)*sum; } printf("%lld\n",ans); return 0; }