hdu 4013树的最小表示

给定一个无根树,求他的子树的个数,子树也是无根树,边和点一一对应即为相等子树。

枚举子集,这样就可以枚举出每种树的构成,然后枚举根节点,dfs求出最小表示来判重。

注意,每一个子集如果是树的话,最多只能被计算一次,但是它的不同表示却都要放到set里(最小表示是对于确定根的)

然后如果他是森林的话,由于枚举子集从小到大,他的每棵树都算过了,所以没有问题

如果是在dfs中每一次都插入一次set,因为相同的子树在set中的表示可能会不一样,不好计数

必须枚举子树,把他们的表示都记录下来,才好判重

换句话说,一颗n个节点的子树,表示法应该是一个N*(1 << N)个二进制位才能表示。

树的最小表示让我想起很久之前学的一个字符串的最小表示

是用类似dfs序来进行描述的

以一个节点为父节点的子树的最小表示是:0,子树的最小表示排序,1

就这样。

#include<bits/stdc++.h>
using namespace std;
set<string> S;
bool gra[20][20];
int visit[20];
int n;

string dfs(int u,int pre)
{
	string cur = "0";
	vector<string> v;
	for(int i = 1; i <= n; i++){
		if (gra[u][i] && visit[i] && i != pre){
			v.push_back(dfs(i,u));
		}
	}
	sort(v.begin(),v.end());
	for(int i = 0; i < v.size(); i++) cur = cur + v[i];
	cur = cur + "1";
	//cout << cur << ' ' << u << ' ' << pre << endl;
	return cur;
}


int main()
{
	int t;
	scanf("%d",&t);
	for(int cas = 1; cas <= t; cas++){
		scanf("%d",&n);
		memset(gra,0,sizeof(gra));
		S.clear();
		for(int i = 0; i < n - 1; i++){
			int from,to;
			scanf("%d %d",&from,&to);
			gra[from][to] = 1;
			gra[to][from] = 1;
		}
		int ans = 0;
		for(int i = 1; i < (1 << n); i++){
			memset(visit,0,sizeof(visit));
			for(int j = 0; j < n; j++){
				if (i & (1 << j)) visit[j + 1] = 1;
			}
			//for(int j = 1; j <= n; j++) printf("%d ",visit[j]);
			//cout << endl;
			int flag = 0;
			for(int j = 0; j < n; j++){
				if (i & (1 << j)) {
					string ss = dfs(j + 1,-1);
					//cout << ss << endl; 
					if (S.find(ss) == S.end()){
						flag = 1;
						S.insert(ss); 
					}
			   }
		    }
		    ans = ans + flag;
		}
		printf("Case #%d: %d\n",cas,ans);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值