HDU 6321 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)
Total Submission(s): 1662    Accepted Submission(s): 677


 

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<vn.

 

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:  6343 6342 6341 6340 6339 

#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
#define MAX 1000000000
#define ms memset
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
/*
题目大意:给定m个操作,
可以加边可以减边。
对于每一次操作输出1到n/2的数量的匹配计数。

由于数据量只有10,考虑状态压缩,
假定s是当前点的状态,
那么加边操作是如果状态s里均没有
x和y两点,那么计数状态dp[新状态]+=dp[s];
减边操作对应着减法。
*/
int n,m;
int x,y,s;
int dp[maxn],ans[15];
int num[3000];

char c;

int main()
{
    for(int i=0;i<=1024;i++)  num[i]=num[i>>1]+(i&1);
    
    int t;scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        s=0,dp[s]=1;

        scanf("%d%d",&n,&m);getchar();
        for(int i=0;i<m;i++)
        {
            scanf("%c",&c);getchar();
            scanf("%d%d",&x,&y);getchar();
            x--,y--;
            s|=(1<<x) , s|=(1<<y);
            if(c=='+')
            {
                for(int i=0;i<=s;i++)
                   if((i&(1<<x))==0 && (i&(1<<y))==0)
                     dp[i^(1<<x)^(1<<y)]=(dp[i^(1<<x)^(1<<y)]+dp[i])%mod;
            }
            else
            {
                for(int i=0;i<=s;i++)
                     if((i&(1<<x))==0 && (i&(1<<y))==0)
                         dp[i^(1<<x)^(1<<y)]=(dp[i^(1<<x)^(1<<y)]-dp[i]+mod)%mod;
            }
            memset(ans,0,sizeof(ans));
            for(int i=0;i<=s;i++)     ans[num[i]/2]+=dp[i],ans[num[i]/2]%=mod;
            for(int i=1;i<=n/2;i++)   printf("%d%c",ans[i],((i==n/2)?'\n':' '));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/81406815