HDU 6321 状态压缩

题目: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;	
} 

猜你喜欢

转载自blog.csdn.net/qq_41603898/article/details/81320504