hdu 6321 hdu多校第三场c题(dp)

Problem C. Dynamic Graph Matching

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 180    Accepted Submission(s): 66


 

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 

思路: dp[ now ][ s ]  表示当前操作后, s 这个点集中 已经匹配的方案数。

那么对如果一个状态 s 这个点集 中没有 u 和 v  这两个点,并且现在要加入u和v的连边,那么我就可以通过s 这个状态转移到aims这个状态,aims 这个状态也就是从 s 和 u,v 点集的并。

同理如果我现在要删除u v这个点集 ,那么对于aims (包括 u v 的点集) 我们可以找到一个状态 i  i  中没有u v两点,我们删除从i转移到aims 的方案数。 

代码: 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N =2005;
ll dp[2][N];
ll yi[40];
ll ans[15];
int cnt[N];

void init_yi()
{
	yi[0]=1;
	for(int i=1;i<=33;i++) yi[i]=yi[i-1]*2;
}

void init_cnt()
{
	for(int i=0;i<N;i++) cnt[i]=__builtin_popcount(i);// 统计1 的位数 
}

int main()
{
	int now,pre;
	int T;
	int u,v;
	char op[5];
	init_yi();
	init_cnt();
	
	scanf("%d",&T);
	int n,m;
	while(T--)
	{
		scanf("%d %d",&n,&m);
		int up=1<<n;
		memset(dp,0,sizeof(dp));
		
		dp[0][0]=1;
		pre=0;  now=1;
		while(m--)
		{
			scanf("%s %d %d",op,&u,&v);
			u--; v--;
			//cout<<"yi "<<yi[u]<<" yiv "<<yi[v]<<endl;
			int tmps=yi[u]|yi[v];
			for(int i=0;i<up;i++) dp[now][i]=0;
			if(op[0]=='+'){
				for(int i=0;i<up;i++){
					dp[now][i]=dp[pre][i];
				}
				
				for(int i=0;i<up;i++){
					if((i&tmps)==0){ // 表示i 这个状态并没有用到u 和v 两个点 
						int aims=(tmps|i);
						dp[now][aims]=(dp[now][aims]+dp[pre][i])%mod; // 我们要想到达aims这个状态可以从i这个状态通过
						// 加u,v这条边转移到aims 这个状态 
					}
				}
			}
			else{
				
				for(int i=0;i<up;i++){
					dp[now][i]=dp[pre][i];
				}
				
				for(int i=0;i<up;i++){
					if((i&tmps)==0){  // 表示i 这个状态并没有用到u 和v 两个点 
						int aims=(tmps|i);
						dp[now][aims]=(dp[now][aims]-dp[pre][i]+mod)%mod;  // 减去之前从i加u,v这条边到aims的方案数 
						//printf("aims %d ***** %lld\n",aims,dp[now][aims]);
					}
				}
			}
			
			memset(ans,0,sizeof(ans));
			for(int i=0;i<up;i++){
				//cout<<" "<<dp[now][i];
				ans[cnt[i]]=(ans[cnt[i]]+dp[now][i])%mod;
			}
			//cout<<endl;
			
			for(int i=2;i<=n;i+=2)
			{
				if(i!=2) printf(" ");
				printf("%lld",ans[i]);
			}
			printf("\n");
			
			now=1-now; pre=1-pre;
		}
		
	}
	
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值