1. 程式人生 > >4455: [Zjoi2016]小星星|狀壓DP|容斥原理

4455: [Zjoi2016]小星星|狀壓DP|容斥原理

out var -s mod ati cto cout erl ber

OrzSDOIR1ak的晨神
能夠考慮狀壓DP枚舉子集,求出僅僅保證連通性不保證一一相應的狀態下的方案數,然後容斥一下就是終於的答案

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<ctime> #include<set> #include<map> using namespace std; bool a[22][22]; long long f[22][22],ans; int head[44],nxt[44],lst[44],q[44]; int n,m,tot,w; void insert(int x,int y) { lst[++tot]=y; nxt[tot]=head[x]; head[x]=tot; lst[++tot]=x; nxt[tot]=head[y]; head[y]=tot; } void dp(int
x,int fa) { for(int i=head[x];i;i=nxt[i]) if(lst[i]!=fa)dp(lst[i],x); for(int i=1;i<=w;i++) { f[x][q[i]]=1; for(int j=head[x];j;j=nxt[j]) if(lst[j]!=fa) { long long tmp=0; for(int k=1;k<=w;k++) if
(a[q[i]][q[k]])tmp+=f[lst[j]][q[k]]; f[x][q[i]]*=tmp; } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); a[x][y]=a[y][x]=1; } for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); insert(x,y); } for(int S=1,T=1<<n;S<T;S++) { w=0; for(int i=1;i<=n;i++) if((1<<i-1)&S)q[++w]=i; long long sum=0;dp(1,0); for(int i=1;i<=w;i++)sum+=f[1][q[i]]; if((w^n)&1) ans-=sum; else ans+=sum; } cout<<ans; return 0; }

4455: [Zjoi2016]小星星|狀壓DP|容斥原理