给出一个图,询问加减边,问你在当时的1匹配,2匹配,3匹配的种类有多种
2匹配=>该图中,选出两条边,连着四个点,完全不重叠的,其余同理
dp[S],S中的所有点,和某些边,是一个count1(S)/2的匹配
dap = 1<< u|1<< v
加边的时候 dp[S] += dp[S^dap] S^dap没有u和v的连边,加入之,(一维数组包括原来的)
注意减边的时候是dp[S] -= dp[S^dap]
#include <iostream>
#include <set>
#include <vector>
#include <map>
#include <algorithm>
#include <cstring>
#define debug(x) //std::cerr << #x << " = " << (x) << std::endl
using namespace std;
typedef long long LL;
const int MAXN = 3e4+17;
const int MOD = 1e9+7;
int main()
{
#ifdef noob
freopen("Input.txt", "r", stdin);
freopen("Output.txt", "w", stdout);
#endif
int t;
cin>>t;
int cnt[10000];
for (int i = 0; i <= 1<<10; ++i)
{
cnt[i] = __builtin_popcount(i);
}
while(t--)
{
int n,m;
cin>>n>>m;
vector<int > dp((1<<n)+1);
dp[0] = 1;
for(int i = 1; i <= m; i++)
{
char cmd[5];
int u,v;
scanf("%s%d%d",&cmd,&u,&v);
u--,v--;
int dap = (1<<u)|(1<<v);
if(cmd[0]=='+')
{
for(int k = 0; k < 1<<n; k++)
if((k&dap)==dap)
dp[k] = (dp[k]+dp[k^dap])%MOD;
}
else
{
for(int k = 0; k <= 1<<n; k++)
if((k&dap)==dap)
dp[k] = (dp[k]-dp[k^dap]+MOD)%MOD;
}
vector<int > ans(6);
for(int k = 0; k < 1<<n; k++)
{
if(cnt[k]%2==0)
ans[cnt[k]/2] = (ans[cnt[k]/2]+dp[k])%MOD;
}
for (int i = 1; i <= n/2; ++i)
{
printf("%lld%c",ans[i],i==n/2?'\n':' ' );
}
}
}
return 0;
}
注意减边的时候是dp[S] -= dp[S^dap] 首先,假设上一步就是加的这条要被现在删的边了,那么显然,在之前做这种调换,是没有影响的,那么,一定存在一种顺序,即上一步就是加这条边,在操作完之后是当前结果,即便事实不是这样.这里我很惊奇,仿佛是从虚空之中取出了这种顺序.