【BZOJ 4455】 [Zjoi2016]小星星 容斥计数

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
",ans);
  return 0;
}
原文地址:https://www.cnblogs.com/TSHugh/p/8470499.html