HDU 6321 Problem C. Dynamic Graph Matching (状压dp)
题意:给定一个N个点的零图,M次操作,添加或删除一条边,每一次操作以后,打印用1,2,…N/2条边构成的匹配数。
分析:因为N的范围很小,所以可以把点的枚举状态用二进制表示集合。用一维数组dp[S]表示二进制集合为S的点集的匹配数。
每次加边操作,从大到小遍历集合,dp[S]+=dp[S-u-v];删边操作,从小到大遍历集合,dp[S]-=dp[S-u-v]。
预处理出每个1024之内每个数对应二进制含有1的个数,每次记录答案就将每个dp[S]加到ans[S]对应的二进制个数]中。
#include<bits/stdc++.h>
using namespace std;
const int maxn =1030;
const int mod = 1e9+7;
typedef long long LL;
void add(int &a,int b){a=a+b<mod?a+b:a+b-mod;}
void del(int &a,int b){a=a-b<0?a-b+mod:a-b;}
int dp[maxn],ans[15],cnt[maxn];
int main()
{
int T,N,M,u,v;
char op[5];
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
int tot=1<<N;
for(int i=0;i<tot;++i)
{
dp[i]=0;
cnt[i] = __builtin_popcount(i);//统计二进制中1的个数
}
dp[0]=1;
while(M--)
{
scanf("%s%d%d",op,&u,&v);
memset(ans,0,sizeof(ans));
u--,v--;
int S = (1<<u)|(1<<v); //取只包含u,v的集合
if(op[0]=='+')
{
for(int t=tot-1;~t;--t)
if(!(t&S)) add(dp[t^S],dp[t]); //加上原来不包含的u,v的集合的匹配数
}
else
{
for(int t=0;t<tot;++t)
if(!(t&S)) del(dp[t^S],dp[t]); //减去原来不包含u,v的集合的匹配数
}
for(int i=1;i<tot;++i) add(ans[cnt[i]],dp[i]);
for(int i=2;i<=N;i+=2) printf("%d%c",ans[i],i<N?' ':'\n');
}
}
return 0;
}