Problem Description
In the mathematical discipline of graph theory, a matching in a graph is a set of edges without common vertices.
You are given an undirected graph with n vertices, labeled by 1,2,…,n. Initially the graph has no edges.
There are 2 kinds of operations :
+ u v, add an edge (u,v) into the graph, multiple edges between same pair of vertices are allowed.
- u v, remove an edge (u,v), it is guaranteed that there are at least one such edge in the graph.
Your task is to compute the number of matchings with exactly k edges after each operation for k=1,2,3,…,n2. Note that multiple edges between same pair of vertices are considered different.
Input
The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.
In each test case, there are 2 integers n,m(2≤n≤10,nmod2=0,1≤m≤30000), denoting the number of vertices and operations.
For the next m lines, each line describes an operation, and it is guaranteed that 1 ≤ u < v ≤n.
Output
For each operation, print a single line containing n2 integers, denoting the answer for k=1,2,3,…,n2. Since the answer may be very large, please print the answer modulo 109+7.
Sample Input
1
4 8
+ 1 2
+ 3 4
+ 1 3
+ 2 4
- 1 2
- 3 4
+ 1 2
+ 3 4
Sample Output
1 0
2 1
3 1
4 2
3 1
2 1
3 1
4 2
Source
2018 Multi-University Training Contest 3
分析:
‘+’
dp[i][S]=dp[i−1][S]+dp[i−1][S−v−u]
d
p
[
i
]
[
S
]
=
d
p
[
i
−
1
]
[
S
]
+
d
p
[
i
−
1
]
[
S
−
v
−
u
]
当S中不包含v和u两个点
‘-’
dp[i][S]=dp[i−1][S]−dp[i−1][S−v−u]
d
p
[
i
]
[
S
]
=
d
p
[
i
−
1
]
[
S
]
−
d
p
[
i
−
1
]
[
S
−
v
−
u
]
当S中不包含v和u两个点
可以用滚动数组来优化,一般来说降掉一维之后dp的顺序很重要,但是这个题我们可以发现DP的顺序是无所谓的,因为当遍历到第i次操作的时候,当前层更新的永远是有(u,v)这两个点的集合状态,而且当前层利用的旧状态都是没有(u,v)这两个点的集合状态,所以DP顺序你可以随意确定,不会影响。
代码
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define bug(x) cout<<"@@ "<<x<<"\n"
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int N = (int) 1e6 + 11;
const int M = (int) 1e6 + 11;
const int INF = (int)0x3f3f3f3f;
const int MOD = (int)1e9 + 7;
#include <ext/rope>
using namespace __gnu_cxx;
inline void add(int &a, int b){ a = a + b < MOD ? a + b : a + b - MOD; } // %符号用多了很费时间,所以可以这样来优化一些
inline void sub(int &a, int b){ a = a - b >= 0 ? a - b : a - b + MOD; }
int cnt[1 << 10], ans[11], dp[1 << 10];
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int _; scanf("%d", &_);
while(_--){
int n, m; scanf("%d%d", &n, &m);
for(int i = 0; i < (1 << n); i++) dp[i] = 0, cnt[i] = __builtin_popcount(i);
dp[0] = 1;
char s[10]; int a, b;
while(m--){
scanf("%s%d%d", s, &a, &b); a--; b--;
int S = (1 << a) | (1 << b);
for(int i = 0; i < (1 << n); i++){
if(!(i & S)){
if(s[0] == '+')
add(dp[ i ^ S], dp[i]);
else
sub(dp[i ^ S], dp[i]);
}
}
memset(ans, 0, sizeof(int) * (n + 2));
for(int i = 1; i < (1 << n); i++) add(ans[cnt[i]], dp[i]);
for(int i = 2; i <= n; i += 2) printf("%d%c", ans[i], i < n ? ' ': '\n');
}
}
return 0;
}