1. 程式人生 > >杭電多校第三場1003 C. Dynamic Graph Matching(狀壓dp 處理圖匹配計數)

杭電多校第三場1003 C. 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): 388    Accepted Submission(s): 148


 

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

Recommend

chendu   |   We have carefully selected several similar problems for you:  6331 6330 6329 6328 6327 

 

【小結】

總碰到狀壓dp,總是束手無策。因為我菜。

【題意】

有一個n點的無向圖,初始時沒有邊,有m次操作,每次可以增加或刪除一條邊(注意,允許重邊的存在)

要求每一次操作之後,輸出匹配數分別為1,2,3...n/2的方案數。

匹配是指:選中一些邊,使得兩兩沒有公共點,即每兩個點可以通過邊匹配起來。

【分析】

二進位制表示集合,對於狀態 i 的每一位,為1則選中,為0則不屬於當前集合。

dp[i] 表示i狀態,集合內所有點都匹配了 的 方案數。

那麼當新增邊u-v時,所有同時包含 uv 的狀態 S 需要更新,dp[S] += dp[S-u-v]  (S-u-v表示狀態S去掉u和v的狀態)

更新dp[i] 時,需要考慮更新時會對答案產生的貢獻。

【程式碼】

/****
***author: winter2121
****/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAX=2e5+5;

ll dp[1<<11]; //dp[i]:i集合內點完全匹配的方案數
int bit[1<<11]; //i的二進位制的1的個數
ll ans[11];
void adjust(ll &x){x=(x%mod+mod)%mod;}
int calc(int x)
{
    int res=0;
    while(x)res++,x-=x&-x;
    return res;
}
int main()
{
    for(int i=0;i<1<<10;i++)bit[i]=calc(i);
    int T,n=10,m,u,v;
    char op[3];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        memset(dp,0,sizeof(dp));
        memset(ans,0,sizeof(ans));
        dp[0]=1;
        while(m--)
        {
            scanf("%s%d%d",op,&u,&v);u--,v--;
            if(op[0]=='+')
            {
                for(int i=(1<<n)-1;i>0;i--)if(((1<<u)&i)&&((1<<v)&i))
                {
                    dp[i]+=dp[i-(1<<u)-(1<<v)];
                    ans[bit[i]]+=dp[i-(1<<u)-(1<<v)]; //對於i集合所有點的匹配,會對ans造成的影響
                    adjust(dp[i]);
                    adjust(ans[bit[i]]);
                }
            }
            else
            {
                for(int i=1;i<1<<n;i++)if(((1<<u)&i)&&((1<<v)&i))
                {
                    dp[i]-=dp[i-(1<<u)-(1<<v)];
                    ans[bit[i]]-=dp[i-(1<<u)-(1<<v)];
                    adjust(dp[i]);
                    adjust(ans[bit[i]]);
                }
            }

            for(int i=2;i<=n;i+=2)
                printf("%lld%c",ans[i],i==n?'\n':' ');
        }
    }
    return 0;
}