Problem C. Dynamic Graph Matching
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 1238 Accepted Submission(s): 516
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
题意:
给定一个 n 个点的无向图,m 次加边或者删边操作。 在每次操作后统计有多少个匹配包含 k = 1,2,..., n 2 条边。
匹配是指边不含公共点。
2 ≤n≤ 10,1 ≤m≤ 30000。
状压DP,将点抽象为二进制的每一位,1则表示该点被选择,0表示该点未被选择。则有连线的点集合可抽象成一数字i。
而要加入的两点被抽象成数字S 。
dp[i]表示集合i的匹配方案数。
如果是添加操作,从大到小遍历若 i&S==0则说明集合i中没有S中的两点,i^S则是加上S后的集合。
状态转移方程:dp[i^S]=dp[i^S]+dp[i] 。
如果是删除操作,从小到大遍历:dp[i^S]=dp[i^S]-dp[i]。
#include<bits/stdc++.h>
#include<cstdio>
#define maxn 100010
#define ll long long
#define mod 1000000007
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int main()
{
int bit[1300];
for(int i=0;i<1300;i++)
bit[i]=__builtin_popcount(i);//计算二进制有几个1
int T;
scanf("%d",&T);
while(T--)
{
int dp[1300];
int ans[1300];
memset(dp,0,sizeof(dp));
dp[0]=1;
int N,m;
scanf("%d%d",&N,&m);
int n=1<<N;
while(m--)
{
getchar();
char c;
int x,y;
scanf("%c%d%d",&c,&x,&y);
x--,y--;
int S=(1<<x)|(1<<y);
if(c=='+')
{
for(int i=n-1;i>=0;i--)
{
if(!(i&S))
{
dp[i^S]+=dp[i];
dp[i^S]=(dp[i^S]%mod+mod)%mod;
}
}
}
else
{
for(int i=0;i<n;i++)
{
if(!(i&S))
{
dp[i^S]-=dp[i];
dp[i^S]=(dp[i^S]%mod+mod)%mod;
}
}
}
memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++)
{
ans[bit[i]]+=dp[i];
ans[bit[i]]=(ans[bit[i]]%mod+mod)%mod;
}
for(int i=2;i<=N;i+=2)
printf("%d%c",ans[i],i<N?' ':'\n');
}
}
return 0;
}