本质思想
两种算法都是解决同一种问题
询问两个东西(我也不知道叫什么了)能否通过某种变换而得到
然后实际上可以对他们的所有状态排序,然后找到最小的进行比较,若一样才一样
字符串的最小表示
字符串的循环同构是指:
news=s[i……n]+s[1……i-1](这里还是要吐槽一下oi wiki这里打错了(当然如果你现在去看发现没什么问题了可能是因为我去修好了XD))
现在给你两个字符串让你求出其是否同构
现在考虑给定一个字符串,如何求出其最小表示
首先考虑给定两个位置i,j,给出一个长度k,如果从i,j开始的字符串一直到i+k,j+k都一样的话,但当前匹配到的字符不同则字符大的那个绝对不是最小表示法,因为必然存在一个字符串比他的字典序小
核心操作
将字典序更大的那个点直接跳到 i(j)+k+1的位置
接下来解释为什么
对于已经匹配的相同的字符串,一定已经是当前字符串中最小的同构方式了
假设不是这样
给定已匹配的部分为cab 那么在得到这个匹配状态之前肯定存在
i在c这个位置,j在a这个位置上的情况,则直接失配,不会存在这样的情况,其他情况以此类推
总之就是i(j)到i(j)+k之间没有比i(j)更优的位置
这里还要注意一点 i和j重合时,要让其中一个数+1
代码
//扒的oi wiki的,毕竟众多讲稿中,他的写法最优美
int k=0,i=0,j=1;
while(k<n&&i<n&&j<n)
{
if(sec[(i+k)%n]==sec[(j+k)%n])
{
k++;
}
else
{
sec[(i+k)%n]>sec[(j+k)%n]?i=i+k+1:j=j+k+1;
if(i==j) i++;
k=0;
}
}
i=min(i,j);
树的最小表示法
树的同构是指,两颗有根树可以通过交换根而变成相同的形态
类似的,我们将树也拍成字符串,我们可以想到dfs序,但由于这里每个点都是等价的
所以我们可以将dfs序改为01序列入为0出为1
直观的,为了使树的01串最小,只要从下到上合并的时候对子树从小到大排序即可
代码
这么简单还想要代码?(其实是我懒得去扒了)