题目:http://acm.hdu.edu.cn/showproblem.php?pid=6321
题意:t组测试
每组n个点,m次操作,是一个无向图。 ‘+’ u v 表示增加一条边u,v ;‘-’则相反,保证减边一定存在。
十个点状态dp,用二进制表示这个点的状态。
代码有每一步的解释
#include <bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
typedef long long ll;
const ll mod=1000000007;
int _,n,q,u,v,t;
int dp[1234][20],f[1234];
char s[20];
using namespace std;
int main()
{
rep(i,1,1024) f[i]=f[i>>1]+(i&1);//初始化,f[i]存储i的二进制有多少个1
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&q);
memset(dp,0,sizeof(dp));
rep(i,0,(1<<n))dp[i][0]=1;// 边数为0的状态有1种,初始化为1
rep(i,0,q)
{
scanf("%s %d %d",s,&u,&v);
u--; v--;//若输入 1,2 要状态表示
// 1:第一位二进制为1, 2:第二位二进制为1
//1=2的0次方 1=2的一次方 所以减减
//很神奇对吧,u减减后2的(u-1)的次方二进制下 1所在的位就是第u位
int Ss=(1<<u)+(1<<v); //上面减减后状态表示
for(int S=0;S<=(1<<n)-1;S++)//枚举各种点集状态
{
if((S&Ss)==Ss)//若这种状态包含输入的两个点则处理
{
for(int j=1;j<=f[S];j++)
{
dp[S][j]+=(s[0]=='+'?dp[S^Ss][j-1]:(mod-dp[S^Ss][j-1]));
// dp[S^Ss][j-1] 是不包含这两个点 且边数减少一
if(dp[S][j]>=mod)
dp[S][j]-=mod;
}
}
}
for(int j=1;j<=n/2;j++)
printf("%d%c",dp[(1<<n)-1][j]," \n"[j==n/2]);
}
}
return 0;
}