题目
思路
前两种是https://www.acwing.com/solution/content/4142/中读到的。
1
我们肯定是想要把两棵树的最小表示找出来,然后看看是否相同。
在这种情况下,我们期望是每个点在其子树内按最长链长度从大到小选择子节点进行DFS,但是如果相同呢?我们就要在链上干同样的事情,理论上我认为记忆性搜索应该可以到 O ( n 2 ) O(n^2) O(n2),但我更认为我打不出这个代码。
2
上一种方法的优化,就是直接把子节点的最小表示求出来,然后子节点的最小表示再按字典序拼起来,然后向上不断合并,最小表示就出来了,最后判断一下即可。
他们说是 O ( n 2 ) O(n^2) O(n2),但是因为有排序,我又觉得不是 O ( n 2 ) O(n^2) O(n2),应该会稍大一些,但是又卡不掉。(上面第一种也是如此。但是如果用类似基数排序的方法确实是 O ( n 2 ) O(n^2) O(n2)的。)
3
我的思路就很暴力了。
p d ( x , y ) pd(x,y) pd(x,y)表示判断 x , y x,y x,y两个子树是不是一样的,怎么判断呢?我们把 x x x的子节点依次与 y y y的子节点进行判断,最后如果发现可以一一匹配的话,则返回 1 1 1,否则返回 0 0 0。
但是时间复杂度如何证明?
很明显,对于同一高度的两个点最多进入 p d pd pd一次,因为对于 p d ( x , y ) pd(x,y) pd(x,y)而言, x x x的子节点 a a a和 y y y的子节点 b b b只会 p d pd pd一次,不管成功与否,代码以后都不会再判断 p d ( x , y ) pd(x,y) pd(x,y)了,所以 a , b a,b a,b也就只会互相 p d pd pd一次。
利用这个,我们就可以得到时间复杂度: O ( n 2 ) O(n^2) O(n2)
暴力出奇迹!!!!
代码
#include<cstdio>
#include<cstring>
#define N 6100
using namespace std;
struct node
{
int y,next;
}a[N],b[N];int len,last[N],tot/*点的个数*/;
int n,fa[N],cnt[N];
void insa(int x,int y)
{
len++;
a[len].y=y;a[len].next=last[x];last[x]=len;
}
void insb(int x,int y)
{
len++;
b[len].y=y;b[len].next=last[x];last[x]=len;
}
char st[N];
int aa[N],bb[N];
int sta[N],top;//sta栈
int v[N],ts;
bool pd(int x,int y)
{
if(cnt[x]!=cnt[y])return 0;
ts++;int now=ts;
for(int k=last[x];k;k=a[k].next)
{
int xx=a[k].y,t=0;
for(int kk=last[y];kk;kk=b[kk].next)
{
int yy=b[kk].y;
if(v[yy]!=now)
{
if(pd(xx,yy)==1)
{
t=1;
v[yy]=now;break;
}
}
}
if(t==0)
{
return 0;
}
}
return 1;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
tot=0;len=0;top=0;memset(last,0,sizeof(last));
memset(a,0,sizeof(a));memset(b,0,sizeof(b));
memset(cnt,0,sizeof(cnt));ts=0;memset(v,0,sizeof(v));
//初始化
scanf("%s",st+1);n=strlen(st+1);
for(int i=1;i<=n;i++)aa[i]=st[i]-'0';
scanf("%s",st+1);
for(int i=1;i<=n;i++)bb[i]=st[i]-'0';
sta[top]=++tot;
for(int i=1;i<=n;i++)
{
if(aa[i]==0)
{
int x=sta[top];
sta[++top]=++tot;cnt[tot]=1;
fa[tot]=x;insa(x,tot);//收一个儿子
}
else cnt[fa[sta[top]]]+=cnt[sta[top]],top--;
}
sta[top]=++tot;
for(int i=1;i<=n;i++)
{
if(bb[i]==0)
{
int x=sta[top];
sta[++top]=++tot;cnt[tot]=1;
fa[tot]=x;insb(x,tot);//收一个儿子
}
else cnt[fa[sta[top]]]+=cnt[sta[top]],top--;
}
if(pd(1,tot/2+1))printf("same\n");
else printf("different\n");
}
return 0;
}