杭电多校第三场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

2018 Multi-University Training Contest 3

Recommend

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

 

Statistic | Submit | Discuss | Note

【小结】

总碰到状压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;
}

猜你喜欢

转载自blog.csdn.net/winter2121/article/details/81293935