P5043

Solution:

In luogu

题意:

给定 \(m\) 棵无根树,对于每棵树求编号与其同构的树的最小编号。

做法

这类树同构的问题,容易想到树哈希。

判断两个两棵树是否同构。

如果两棵树中的 每一个节点 的哈希值都相等,那么这两棵树同构。

注意到 \(1 \leq n, m \leq 50\),所以我们先得到每棵树所有节点的哈希值,然后直接暴力判断即可。时间复杂度约为 \(\mathcal{O}(N ^ 2 M)\)

如何得到哈希值

因为数据较小,我们可以使用一种简单的方法。

首先,对于叶子节点,我们将哈希值设为 \(1\)

否则对于非空节点,我们先求出其子节点的哈希值,然后将其排序,接着运用类似字符串哈希的方法,将这些子树的哈希值当做字符进行处理。

实现方式:

int hash(int u, int fa)
{
	if (G[u].size() == 1 && fa != 0) return 1; 
	else
	{
		vector <int> has;//子树的哈希值 
		int res = 1;
		for (int i = 0; i < G[u].size(); i ++ )
		{
			int v = G[u][i];
			if (v == fa) continue;
			has.push_back(hash(v, u));
		}
		sort(has.begin(), has.end());	
		for (int i = 0; i < has.size(); i ++ ) res = (res * p + has[i]) % mod;
		return res;
	}
}

tips

因为有多棵树,所以我们将每棵树用一个结构体存起来,这样使用会更方便。

代码

#include <bits/stdc++.h>

#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define int unsigned long long

const int N = 60, M = 50, K = 120;
const int p = 13331, mod = 1e9 + 7;

using namespace std;

//如果两棵树同构,这两棵树中每一个结点的哈希值一定是相同的。

int m, n;

struct graph

{
	vector <int> G[N];
	void add(int u, int v)
	{
		G[u].push_back(v), G[v].push_back(u); 
	}
	int hash(int u, int fa)
	{
		if (G[u].size() == 1 && fa != 0) return 1; 
		else
		{
			vector <int> has;//子树的哈希值 
			int res = 1;
			for (int i = 0; i < G[u].size(); i ++ )
			{
				int v = G[u][i];
				if (v == fa) continue;
				has.push_back(hash(v, u));
			}
			sort(has.begin(), has.end());	
			for (int i = 0; i < has.size(); i ++ ) res = (res * p + has[i]) % mod;
			return res;
		}
	}
}tree[N]; 

int ha[N][N];

signed main()

{
    IOS;

	cin >> m;
	for (int i = 1; i <= m; i ++ )
	{
		cin >> n; 
		graph& t = tree[i];
		for (int j = 1; j <= n; j ++ )
		{
			int k;
			cin >> k;
			if (!k) continue;
			t.add(j, k);
		}
		for (int j = 1; j <= n; j ++ ) 
		{
			int h = t.hash(j, 0);
			ha[i][j] = h;
		} 
		sort(ha[i] + 1, ha[i] + n + 1); 
		for (int j = 1; j <= i; j ++ )
		{
			bool ch = true;
			for (int k = 1; k <= n; k ++ )
			{
				if (ha[j][k] != ha[i][k]) 
				{
					ch = false;
					break;
				}
			}
			if (ch)
			{
				cout << j << '\n';
				break;
			}
		}
	}
}
posted @ 2023-07-19 07:55  恋暗  阅读(13)  评论(0)    收藏  举报