-
Problem C. Dynamic Graph Matching
HDU - 6321 - 题意:给定一个N个点的零图,M次操作,添加或删除一条边,每一次操作以后,打印用1,2,...N/2条边构成的匹配对数目。
- 匹配对是指的 每条边连接的两个点,不能重复,例如 一共四个点 ,可以选择 1-2 一条边 3 -4 一条边 不能交叉
- 两个点可以重复多条边,也就是 可以有 多个 1-2 被认为是不同的。
- 思路:因为N的范围很小,所以可以把点的枚举状态用二进制表示集合。
- 用一维数组dp[S]表示二进制集合为S的点集的匹配数。
- 每次加边操作,遍历集合,dp[S]+=dp[S|(1<<u)&(1<<v)];删边操作,遍历集合dp[S]-=dp[S|(1<<u)&(1<<v)];。
- 每个数对应二进制含有1的个数,每次记录答案就将每个dp[S]加到ans[S对应的二进制个数]中
-
#include<bits/stdc++.h> using namespace std; #define mod 1000000007 #define maxn 1<<12 int t,n,m,ans[15],tot,u,v; int dp[maxn],sum[maxn],ad; char op[5]; int main() { for(int i=0; i<=(1<<11); i++) sum[i]=__builtin_popcount(i); scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); tot=(1<<n); for(int i=0; i<tot; i++) dp[i]=0; dp[0]=1; while(m--) { scanf("%s%d%d",op,&u,&v); u--,v--; ad=((1<<u)|(1<<v)); if(op[0]=='+') { for(int i=0; i<tot; i++) if((ad&i)==0) dp[ad|i]=(dp[ad|i]+dp[i])%mod; } else { for(int i=0; i<tot; i++) if((ad&i)==0) dp[ad|i]=(dp[ad|i]-dp[i]+mod)%mod; } memset(ans,0,sizeof(ans)); for(int i=0; i<tot; i++) ans[sum[i]]=(ans[sum[i]]+dp[i])%mod; for(int i=2; i<=n; i+=2) if(i==n)printf("%d\n",ans[i]); else printf("%d ",ans[i]); } } return 0; }