2018 Multi-University Training Contest 3:Problem C. Dynamic Graph Matching(状压DP)

Problem C. Dynamic Graph Matching
Time Limit: 8000/4000 MS (Java/Others)
Memory Limit: 524288/524288 K (Java/Others)

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 , . . . , n 2 . 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 , n mod 2 = 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 , . . . , n 2 . Since the answer may be very large, please print the answer modulo 10 9 + 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
思路:设 d [ i ] [ S ] 表示前 i 次操作之后, S 集合的点已经匹配的方案数。
对于加边操作,显然 d [ i ] [ S ] = d [ i 1 ] [ S ] + d [ i 1 ] [ S u v ]
i 这一维可以省略,从大到小遍历 S d [ S ] + = d [ S u v ]
对于删边操作,注意到加边操作的顺序不影响结果,可以假设第 i 1 次操作是加入要删除的边。
将加边操作的更新倒过来,得到:从小到大遍历 S d [ S ] = d [ S u v ]

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
typedef long long ll;
int d[1<<10];
int ans[10];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(d,0,sizeof d);
        memset(ans,0,sizeof ans);
        d[0]=1;
        while(m--)
        {
            char op[3];
            int x,y;
            scanf("%s%d%d",op,&x,&y);
            x--;
            y--;
            if(op[0]=='+')
            {
                for(int i=(1<<n)-1;i>=0;i--)
                {
                    if((i&(1<<x))==0)continue;
                    if((i&(1<<y))==0)continue;
                    if(d[i^(1<<x)^(1<<y)]==0)continue;
                    (d[i]+=d[i^(1<<x)^(1<<y)])%=MOD;
                }
            }
            else
            {
                for(int i=0;i<(1<<n);i++)
                {
                    if((i&(1<<x))==0)continue;
                    if((i&(1<<y))==0)continue;
                    if(d[i^(1<<x)^(1<<y)]==0)continue;
                    (d[i]-=d[i^(1<<x)^(1<<y)])%=MOD;
                    (d[i]+=MOD)%=MOD;
                }
            }
            for(int i=2;i<(1<<n);i++)
            {
                if(d[i]==0)continue;
                (ans[__builtin_popcount(i)/2]+=d[i])%=MOD;
            }
            for(int i=1;i<=n/2;i++)printf("%d%c",ans[i],i==n/2?'\n':' ');
            for(int i=1;i<=n/2;i++)ans[i]=0;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81296441