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;
}