更容易理解 有根树的同构 无根树的同构

点击打开链接

只有一个点入度为0的树是外向树,只有一个点出度为0的树是内向树,这两种是典型的有根树

平时见到的无向图中的树是无根树

1.判断树同构本质是哈希,每个点的权值是这个点的子树的权值和,这里所谓的权值是随机数产生的

由于随机性,树上某一组合不同都会导致最终的结果不一样,所以只要判断根的权值是否相等就可以确定同构

2.随机性决定了不确定性,但正确率还是很高

3.可以不用哈希,用“最小表示”表示出一个点的子节点,再比较最小表示产生的序列是否相同,代码烦,比较复杂,不见得快

poj 1635

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define mod 9997
char str1[10000];
char str2[10000];
int h[10000],len,cur;
char *p;

int hashing(int j)
{
	int sum=h[j];
	while(*p!='\0'&&*p++=='0') //每次检查是否1时还加1,使回溯时跳出循环
	{
		sum=(sum+hashing(j+1)*h[j])%mod;
	}
	return (sum*sum)%mod;
}

int main ()
{
	for(int i=0;i<10000;++i)
		h[i]=rand()%mod;
	int test;scanf("%d",&test);
	while(test--)
	{
		scanf("%s%s",str1,str2);
		if(strlen(str1)!=strlen(str2))
		{
			printf("different\n");
			continue;
		}
		len=strlen(str1);
		p=str1;
		int a=hashing(1);
		p=str2;
		int b=hashing(1);// 多次hash 可以避免冲突,提高正确率
		if(a==b)
			printf("same\n");
		else printf("different\n");
	}
	system("pause");
	return 0;
}

ustc 1117

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
using namespace std;
#define mod 9973
int h[1050];
vector<int>s[1050];
vector<int>p[1050];
int vis[1050];
int n;

int Hash(int cur,int depth)
{
	int sum=h[depth];vis[cur]=1;
	for(int i=0;i<s[cur].size();++i)
		if(!vis[s[cur][i]])
			sum=(sum+Hash(s[cur][i],depth+1)*h[depth])%mod;
	return (sum*sum)%mod;
}
int Hash2(int cur,int depth)
{
	int sum=h[depth];vis[cur]=1;
	for(int i=0;i<p[cur].size();++i)
		if(!vis[p[cur][i]])
			sum=(sum+Hash2(p[cur][i],depth+1)*h[depth])%mod;
	return (sum*sum)%mod;
}

int main ()
{
	for(int i=0;i<1040;++i)
		h[i]=rand()%mod;
	int test;scanf("%d",&test);
	while(test--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
			s[i].clear(),p[i].clear();
		int u,v;
		for(int i=1;i<n;++i)
		{
			scanf("%d%d",&u,&v);
			s[u].push_back(v);
			s[v].push_back(u);
		}
		for(int i=1;i<n;++i)
		{
			scanf("%d%d",&u,&v);
			p[u].push_back(v);
			p[v].push_back(u);
		}
		memset(vis,0,sizeof(vis));
		int a=Hash(1,1);
		bool flag=false;
		for(int i=1;i<=n;++i)
		{
			memset(vis,0,sizeof(vis));
			int b=Hash2(i,1);
			if(a==b)
				flag=true;
			if(flag)
				break;
		}
		if(flag)
			printf("same\n");
		else printf("different\n");
	}
	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值