题意:
给定n个点的无根树,点x是好点当且仅当:
1.x的度数大于1
2.以x为根时,x的所有子树结构相同
找到度数最大的好点,输出这个最大度数
数据范围:n<=4e3
解法:
枚举每个点作为根,计算子树是否同构即可,同构可以用树Hash来做
枚举部分用换根dp优化
ps:
我咋感觉这道题我写出来的换根和以前的换根写法不太一样。。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=4e3+5;
//双Hash,且质数和模数都不同
const int p1=131,p2=1331;
const int mod1=1e9+7,mod2=998244353;
int base1[maxm],base2[maxm];
void H_init(){
base1[0]=base2[0]=1;
for(int i=1;i<maxm;i++){
base1[i]=base1[i-1]*p1%mod1;
base2[i]=base2[i-1]*p2%mod2;
}
}
struct H{
int h1,h2,len;
friend bool operator<(H a,H b){
if(a.h1!=b.h1)return a.h1<b.h1;
if(a.h2!=b.h2)return a.h2<b.h2;
return a.len<b.len;
}
bool eq(H a){
return h1==a.h1&&h2==a.h2&&len==a.len;
}
H merge(H a){
H ans;
ans.h1=(h1*base1[a.len]%mod1+a.h1)%mod1;
ans.h2=(h2*base2[a.len]%mod2+a.h2)%mod2;
ans.len=len+a.len;
return ans;
}
};
//
vector<int>g[maxm];
int n;
//
H d[maxm];
H last[maxm];
bool cmp(int a,int b){//按Hash值排序,这样可以保证相同构树合并子树得到的Hash值相同
return d[a]<d[b];
}
int ans=-1;
//
void dfs(int x,int fa){//只合并子树节点
for(int v:g[x]){
if(v==fa)continue;
dfs(v,x);
}
d[x]={1,1,1};
sort(g[x].begin(),g[x].end(),cmp);
for(int v:g[x]){
if(v==fa)continue;
d[x]=d[x].merge(d[v]);
}
}
void dfs2(int x,int fa){//合并父节点
//假设x是根,尝试用x更新答案
int ok=1;
H temp={0,0,0};//{0,0,0}表示空
for(int v:g[x]){//判断子树是否同构
if(temp.len==0)temp=d[v];
else if(!d[v].eq(temp)){
ok=0;break;
}
}
if(ok&&g[x].size()>1){
ans=max(ans,(int)g[x].size());
}
//
vector<H>order;//存点x的子节点Hash合并顺序
for(int v:g[x]){//d[fa]也被放进去了
order.push_back(d[v]);
}
vector<H>st=order;//st[i]表示以点i为起点的Hash值
vector<H>ed=order;//ed[i]表示以点i为终点的Hash值
for(int i=(int)order.size()-2;i>=0;i--){
st[i]=st[i].merge(st[i+1]);
}
for(int i=1;i<(int)order.size();i++){
ed[i]=ed[i-1].merge(ed[i]);
}
//
int len=g[x].size();
for(int i=0;i<len;i++){
int v=g[x][i];
if(v==fa)continue;
H f={1,1,1};
if(i>0)f=f.merge(ed[i-1]);
if(i<len-1)f=f.merge(st[i+1]);
//这时候f是当v为根时,v->x的Hash值
d[x]=f;//将d[x]替换为f,这样检查v的时候可以直接假设v是根
dfs2(v,x);
}
}
signed main(){
H_init();
cin>>n;
for(int i=1;i<n;i++){
int a,b;cin>>a>>b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1,0);
d[0]={0,0,0};
dfs2(1,0);
cout<<ans<<endl;
return 0;
}