【HDU5732 2016 Multi-University Training Contest 1J】【树哈希模板 无根树的同构】Subway 对应两棵树的匹配关系

Subway

Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 486    Accepted Submission(s): 68
Special Judge


Problem Description
jiefangxuanyan and yiyi cat are universally acknowledged model couples. Once jiefangxuanyan has time, he takes a train to yiyi cat’s city and meet her. This time, as usual, jiefangxuanyan gets out from the railway station, and enters the subway, only to find that the subway stations of the whole city changes their names!

As a direction idiot, jiefangxuanyan felt helpless with this situation. He called yiyi cat for help. Because the subway map is so complicated, she can’t remember it either. Fortunately, only the names of the stations changed, the structure of subway lines is the same. So she picks out the old map to make a mapping.

But mapping such a confused subway map is definitely a difficult task. So she has to use the computer. Unfortunately, she just spilt wonton soup into her computer. So, yiyi cat asked you for help, hoping you can help her with this problem.

The subway in the city forms a tree, with N subway stations and N-1 subway lines. Any pair of stations are connected with one or more subway lines. You need to find a bijective mapping from the old names to the new names, that for each pair of stations connected by exactly one line in the old map, their new names are also connected by exactly one line in the new map.
 

Input
The input has multiple test cases, please process to the end of file.

For each test case, the first line is an integer   N(1N100000) .

In the following   N1  lines, each line has two space-separated string, as two stations connected by one line in the old map.

In the following   N1  lines, each line has two space-separated string, as two stations connected by one line in the new map.

Station names are no longer than 10 characters, and only consists of lowercase letters (a~z).
 

Output
For each test case, output   N  lines.

Each line consists two space-separated string, as the old name and its corresponding new name.

Both the names appeared in the old and new subway map should appear exactly once in the output.

You can output the names in any order. And if there are multiple valid mappings, output any one.

Names in the old map and the new map may be the same, but this does not mean these two stations are the same.
 

Sample Input
  
  
3 a b b c b a a c
 

Sample Output
  
  
b a a b c c
 

Author
HIT
 

Source
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int T;
map<string, int>mop[2]; int ID[2];
string S[2][N];
vector<int>a[2][N];
vector<int>core[2];
char s[10];
int n;
int O()
{
	scanf("%s", s);
	if (!mop[T].count(s))mop[T][s] = ++ID[T];
	int o = mop[T][s]; S[T][o] = s;
	return o;
}
int son[N], mxp[N], rt;
void coredfs(int x, int fa)
{
	son[x] = 1;
	mxp[x] = 0;
	for (int i = a[T][x].size() - 1; ~i; --i)
	{
		int y = a[T][x][i];
		if (y == fa)continue;
		coredfs(y, x);
		son[x] += son[y];
		gmax(mxp[x], son[y]);
	}
	gmax(mxp[x], n - son[x]);
	if (mxp[x] < mxp[rt])
	{
		core[T].clear(); core[T].push_back(rt = x);
	}
	else if (mxp[x] == mxp[rt])core[T].push_back(x);
}
void findcore()
{
	mxp[rt = 0] = 1e9;
	coredfs(1, 0);
	if (core[T].size() < 1 || core[T].size() > 2)while (1);
}
const int MAGIC = 111111;
UL powMod(UL x, int p)
{
	UL y = 1;
	while (p)
	{
		if (p & 1)y *= x;
		x *= x;
		p >>= 1;
	}
	return y;
}
struct Hash
{
	int o;
	int len; UL val;
	Hash() :o(-1), len(0), val(0) {}
	Hash(char ch) :len(1), val(ch) {}
	Hash(int l, int v) :len(l), val(v) {}
	bool operator < (const Hash& b)
	{
		return val < b.val;
	}
	bool operator == (const Hash& b)
	{
		return len == b.len && val == b.val;
	}
	Hash operator + (const Hash&b)
	{
		return Hash(len + b.len, val * powMod(MAGIC, b.len) + b.val);
	}
};
Hash self[2][N];
vector<Hash>child[2][N];
void GetHash(int x, int fa)
{
	child[T][x].clear();
	for (int i = a[T][x].size() - 1; ~i; --i)
	{
		int y = a[T][x][i];
		if (y == fa)continue;
		GetHash(y, x);
		child[T][x].push_back(self[T][y]);
	}
	sort(child[T][x].begin(), child[T][x].end());
	self[T][x] = Hash();
	for (auto & it : child[T][x])self[T][x] = self[T][x] + it;
	self[T][x] = Hash('(') + self[T][x] + Hash(')');
	self[T][x].o = x;
}
void match(int x, int y)
{
	//printf("%s %s\n", S[0][x].c_str(), S[1][y].c_str());
	cout << S[0][x] <<  " " << S[1][y] << "\n";
	for (int i = child[0][x].size() - 1; ~i; --i)
	{
		int xx = child[0][x][i].o;
		int yy = child[1][y][i].o;
		match(xx, yy);
	}
}
void tryit()
{
	for (int i = 0; i < core[0].size(); ++i)
	{
		for (int j = 0; j < core[1].size(); ++j)
		{
			int rt0 = core[0][i]; T = 0; GetHash(rt0, 0);
			int rt1 = core[1][j]; T = 1; GetHash(rt1, 0);
			if (self[0][rt0] == self[1][rt1])
			{
				match(rt0, rt1);
				return;
			}
		}
	}
	while (1);//判定是否会出现无法匹配同构的情况
}
int main()
{
	//fre();
	while (~scanf("%d", &n))
	{
		for (T = 0; T < 2; ++T)
		{
			for (int i = 1; i <= n; ++i)a[T][i].clear();
			mop[T].clear(); ID[T] = 0;
			for (int i = 1; i < n; ++i)
			{
				int x = O(); int y = O();
				a[T][x].push_back(y);
				a[T][y].push_back(x);
			}
			findcore();
		}
		tryit();
	}
	return 0;
}
/*
【trick&&吐槽】
妈蛋,这题本来只是一个树同构
让我读题读成了求图的同构,自己加大了题目难度。我是sb!
知道是求树同构之后,这道题的竟然被我一下子写AC了!

【题意】
给你一棵树,树上的每个节点对应着一个字符串。
告诉你边的联通关系。

后来,这棵树的节点可能改了名字,
我们再告诉你边的联通关系。

也就是说,这两棵树是同构的,只是我们不知道具体的同构关系。
问你可能的同构对应关系,并完成节点的匹配

【类型】
树哈希 树同构

【分析】
首先,要知道以下性质——
树的重心和中心都最多只有2个。
于是,我们不妨一个dfs找到树的重心,并把其记录下来。
然后,我们知道重心了,便可以做树哈希。
树哈希的权值如果相同,说明对应关系找到了。
在树哈希成功的基础上,我们递归匹配子儿子的对应关系即可。

【时间复杂度&&优化】
O(nlogn) log是由于排序导致的

*/



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值