题目链接:Dynamic Graph Matching
题意
定义一种图的匹配:在图上选择任意条边,在被选择的边中任意两条边之间没有公共点,则这些边就是图上的一种匹配。
在一个 n n 个节点的图上,最初这张图上的边数为 ,有 m m 次操作,每次操作为以下两种中的一种:
- :在节点 u u 和节点 之间添加一条边;
- − u v − u v :删掉一条在节点 u u 和 之间的边,在删边之前保证节点 u,v u , v 之间至少存在一条边。
在每次操作之后,对于每一个 k (k∈[1,n2]) k ( k ∈ [ 1 , n 2 ] ) ,输出图上边数为 k k 的匹配的数量,两个节点之间的多条边视为不同的边。
输入
第一行为一个整数 ,接下去有 T T 组数据,每组数据第一行为两个整数 ,接下去 m m 行每行由一个字符 和两个数字 u,v (1≤u,v≤n) u , v ( 1 ≤ u , v ≤ n ) 组成,表示一次操作。
输出
对于每一次操作,输出 n2 n 2 个整数,分别表示当 k∈[1,n2] k ∈ [ 1 , n 2 ] 时,图上边数为 k k 的匹配数量对 取模的结果。
样例
输入 |
---|
1 4 8 + 1 2 + 3 4 + 1 3 + 2 4 - 1 2 - 3 4 + 1 2 + 3 4 |
输出 |
1 0 2 1 3 1 4 2 3 1 2 1 3 1 4 2 |
题解
我们用 2n 2 n 个整数对应图上点的选择方案,整数的第 i i 个二进制位为 表示不选择第 i i 个点,否则表示选择第 个点,则一个数字表示一种选择点的状态。用 dp[i] d p [ i ] 记录某种匹配的边覆盖的点的状态为 i i 的情况下,匹配的数量,则 中 1 1 的个数必须为偶数,否则匹配数量就为 。
每当节点 u u 和 之间的边的数量 +1 + 1 或 −1 − 1 ,就会影响所有选点状态同时包含 u,v u , v 两点的 dp d p 值,如果 i i 的第 和 v v 位都为 ,则 dp[i]+=d×dp[i−(1<<v)−(1<<u)] d p [ i ] + = d × d p [ i − ( 1 << v ) − ( 1 << u ) ] ,当 ch c h 为+
时 d=1 d = 1 ,否则 d=−1 d = − 1 。
初始状态 dp[0]=1 d p [ 0 ] = 1 ,用 ans[i] a n s [ i ] 记录在匹配边的数量为 i i 时的总方案数,设 为数字 i i 的二进制位中 的数量,则 ans[j]=∑2ni=0dp[i] a n s [ j ] = ∑ i = 0 2 n d p [ i ] ,其中 j=biti2 j = b i t i 2 。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <unordered_set>
#include <unordered_map>
using namespace std;
#define LL long long
const int maxn = 1000 + 100;
const int MOD = 1000000000 + 7;
int T, n, m, u, v, d;
char ch[2];
int dp[maxn], ans[maxn], bit[maxn];
int add(int a, int b) {
int ret = a + b;
if(ret < 0) {
return ret + MOD;
}
if(ret >= MOD) {
return ret - MOD;
}
return ret;
}
void solve(int u, int v, int d) {
int tmp = (1 << u) | (1 << v);
for(int i = 1; i < (1 << n); ++i) {
if((bit[i] & 1) == 1) {
continue;
}
if((i & tmp) == tmp) {
dp[i] = add(dp[i], d * dp[i ^ tmp]);
ans[bit[i] >> 1] = add(ans[bit[i] >> 1], d * dp[i ^ tmp]);
}
}
}
int main() {
#ifdef LOCAL
freopen("test.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif // LOCAL
ios::sync_with_stdio(true);
for(int i = 0; i < maxn; ++i) {
bit[i] = 0;
for(int j = 0; j < 10; ++j) {
if(((i >> j) & 1) == 1) {
++bit[i];
}
}
}
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
memset(dp, 0, sizeof(int) * (1 << n));
memset(ans + 1, 0, sizeof(int) * (n >> 1));
dp[0] = 1;
for(int i = 0; i < m; ++i) {
scanf("%s%d%d", ch, &u, &v);
d = ch[0] == '+'? 1: -1;
solve(u - 1, v - 1, d);
for(int j = 1; j <= (n >> 1); ++j) {
if(j != 1) {
printf(" ");
}
printf("%d", ans[j]);
}
printf("\n");
}
}
return 0;
}