Dynamic Graph Matching 【状压dp】

来源

https://vjudge.net/contest/397452#problem/C

思路

n只有10,可以状态压缩n个点所有的状态。
dp[i]表示某种状态的取法个数。
设新加入的边为(u,v),状态转移:dp[i] -> dp[i ^ (1<<(u-1)) ^ (1<<(v-1))] , (i>>(u-1)&1 == 0 , i>>(v-1)&1 == 0)
设新删去的边为(u,v),状态转移:dp[i] -> dp[i ^ (1<<(u-1)) ^ (1<<(v-1))] , (i>>(u-1)&1 == 1 , i>>(v-1)&1 == 1)
预处理所有状态相应地边数k(二进制下1的个数除以2),可以加速防止卡常。
询问时遍历所有状态加入ans[k]中即可以统计出所有的答案。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll M=1e9+7;

ll dp[2010],num[2010],ans[20];

inline ll fmod(ll x,ll M){return x>=M?x%M:x;}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	for (int i=0; i<1024; i++){
		int p=i;
		while (p){
			if (p&1) num[i]++;
			p>>=1;
		}
		num[i]>>=1;
	}
	int t;
	cin>>t;
	while (t--){
		int n,m;
		cin>>n>>m; 
		for (int i=0; i<(1<<n); i++) dp[i]=0;	
		dp[0]=1;
		for (int i=1; i<=m; i++){
			string op;
			int u,v;
			cin>>op>>u>>v;
			if (op[0]=='+'){
				for (int i=0; i<(1<<n); i++){
					if (!((i>>(u-1))&1) && !((i>>(v-1))&1)){
						int j=i^(1<<(u-1))^(1<<(v-1));
						dp[j]=fmod(dp[j]+dp[i],M);
					}
				}
			}
			if (op[0]=='-'){
				for (int i=0; i<(1<<n); i++){
					if (((i>>(u-1))&1) && ((i>>(v-1))&1)){
						int j=i^(1<<(u-1))^(1<<(v-1));
						dp[i]=fmod(dp[i]-dp[j]+M,M);
					}
				}
			}
			for (int i=1; i<=(n>>1); i++) ans[i]=0;
			for (int i=0; i<(1<<n); i++) ans[num[i]]=fmod(ans[num[i]]+dp[i],M);
			for (int i=1; i<=(n>>1); i++){
				if (i!=1) cout<<" ";
				cout<<ans[i];
			}
			cout<<"\n";
		}
	}
	return 0;
} 
posted @ 2020-09-29 16:22  Synnn  阅读(158)  评论(0编辑  收藏  举报