hdu6321

题意:给出n个点,q次操作,每次增加一个边,或删除一个边。

问你每次操作后图中的匹配数为k的方案有多少种。

思路:看到n=10,可以想到暴力枚举每个状态。因为操作数右30000种,可以想到状态转换,所以可以使用状压dp。

要预先处理好每个数字含有的1的个数,还有含有偶数个1的点要预先存储一下。不然会T,然后我们根据每个操作后所含的点来转移状态。

#include <bits/stdc++.h>
using namespace std;

int dp[2][2005];
const int mod=1e9+7;
void add(int &x, int y)
{
    x += y;
    if(x >= mod) x -= mod;
}
void sub(int &x, int y)
{
    x -= y;
    if(x < 0) x += mod;
}
int ans[6];
int bi[2005];
int sta[2005];
int num[2005];
int main()
{
	int cnt=0;

    for(int i=0; i<1024; ++i)
    {
        num[i]= num[i>>1]+(i&1);//i的二进制有几个1
        if(~num[i]&1) sta[cnt++] = i;//sta保存偶数个1的二进制数
    }
	int t;
    for(scanf("%d",&t);t;--t)
	{
		int n,q;
        scanf("%d%d",&n,&q);
		memset(dp,0,sizeof(dp));
		int now=0;
		dp[0][0]=1;
		while(q--)
		{
			memset(ans,0,sizeof(ans));
			char s[2];
			int x,y;
			scanf("%s%d%d",s,&x,&y);
			x--;
			y--;
			int tmp=(1<<x)|(1<<y);
			if(s[0]=='+')
			{
				for(int i=0; i<cnt&&sta[i]<(1<<n); i++)		//因为我们求的是图的完全匹配数,所以肯定是含有偶数个点的图,								
				{											//枚举偶数个点的状态 
					int cur=sta[i];
					dp[now^1][cur]=dp[now][cur];
					if((cur&tmp)==tmp) add(dp[now^1][cur],dp[now][cur^tmp]);
					add(ans[num[cur]>>1],dp[now^1][cur]);
				}
			}
			else
			{
				for(int i=0; i<cnt&&sta[i]<(1<<n); i++)
				{
					int cur=sta[i];
					dp[now^1][cur]=dp[now][cur];
					if((cur&tmp)==tmp) sub(dp[now^1][cur],dp[now][cur^tmp]);
					add(ans[num[cur]>>1],dp[now^1][cur]);
				}
			}
            now ^= 1;
            for(int i=1; i<=n/2; ++i) printf("%d%c",ans[i],i==n/2?'\n':' ');
		}

	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37632935/article/details/81507269