HDU - 6321 Dynamic Graph Matching (狀壓dp)
Problem C. Dynamic Graph Matching
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 2138 Accepted Submission(s): 872
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
題意:給定一個N個點的無向圖,M次操作,新增或刪除一條邊,每一次操作以後,列印用1,2,...N/2條邊構成的匹配數。
思路:因為N的範圍很小,所以可以把點的列舉狀態用二進位制表示集合。用一維陣列dp[S]表示二進位制集合為S的點集的匹配數。每次加邊操作,從大到小遍歷集合(對後面的狀態不產生影響),dp[S]+=dp[S-u-v](請細細品味這個狀態轉移);刪邊操作,從小到大遍歷集合,dp[S]-=dp[S-u-v]。預處理出每個1024之內每個數對應二進位制含有1的個數,每次記錄答案就將每個dp[S]加到ans[S對應的二進位制個數]中。
參考部落格http://www.cnblogs.com/xiuwenli/p/9398342.html
程式碼:
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const LL mod=1e9+7;
const LL N=1e3+100;
LL dp[N],ans[15],cnt[N];
int main()
{
LL T;
scanf("%lld",&T);
while(T--)
{
mem(dp,0);
mem(ans,0);
mem(cnt,0);
dp[0]=1;
LL n,m;
char s[5];
LL x,y;
scanf("%lld%lld",&n,&m);
LL k=1<<n;
for(LL i=0; i<k; i++)
{
LL x=i;
while(x)
{
if(x&1) cnt[i]++;
x>>=1;
}
}
while(m--)
{
scanf("%s%lld%lld",s,&x,&y);
x--,y--;
LL S=(1<<x)|(1<<y);
if(s[0]=='+')
{
for(LL i=k-1; ~i; i--)
if(!(S&i)) dp[S^i]=(dp[S^i]+dp[i])%mod;
}
else
{
for(LL i=0; i<k; i++)
if(!(S&i)) dp[S^i]=(dp[S^i]-dp[i]+mod)%mod;
}
for(LL i=0; i<k; i++) ans[cnt[i]]+=dp[i];
for(LL i=2; i<=n; i+=2)
{
if(i!=2) printf(" ");
printf("%lld",ans[i]%mod);
}
printf("\n");
mem(ans,0);
}
}
}