注意到若两个点为根的树深度不同一定不同构,因此答案的下界为
⌈
d
2
⌉
\lceil \frac{d}{2}\rceil
⌈2d⌉(
d
d
d为直径长度),并且容易达到下界。
若
d
d
d为偶数,我们取原树的中心(直径的中点,在边上)为
m
i
d
mid
mid,容易证明以
m
i
d
mid
mid为根后,任意一层的点都需要儿子数目相同,于是根据原树可以得到每一层儿子数目的下界,容易求出最小叶子数目。
若
d
d
d为奇数也类似,不过需要考虑一种特殊情况,即我们不取原树的中心为
m
i
d
mid
mid,而是取中心的某条邻边的中点为
m
i
d
mid
mid,这样不会增大答案,并且可能能取到更小的叶子数目。
暴力实现时间复杂度为
O
(
n
2
)
\mathcal O(n^2)
O(n2)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector <int> e[105];
int fa[105],dep[105],maxd[105];
int dfs1(int x) {
int ans=x;
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa[x]) {
int u=e[x][i];
fa[u]=x;dep[u]=dep[x]+1;
int t=dfs1(u);
if (dep[t]>dep[ans]) ans=t;
}
return ans;
}
void dfs2(int x) {
int s=0;
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa[x]) {
s++;
int u=e[x][i];
fa[u]=x;dep[u]=dep[x]+1;
dfs2(u);
}
maxd[dep[x]]=max(maxd[dep[x]],s);
}
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
dep[1]=1;fa[1]=0;
int rt1=dfs1(1);
dep[rt1]=1;fa[rt1]=0;
int rt2=dfs1(rt1);
int len=((dep[rt2]+1)>>1);
printf("%d ",len);
if (dep[rt2]&1) {
int mid=rt2;
for(int i=1;i<len;i++) mid=fa[mid];
memset(maxd,0,sizeof(maxd));
dep[mid]=1;fa[mid]=0;
dfs2(mid);
ll s=1;
for(int i=1;i<len;i++) s*=maxd[i];
ll ans=s;
for(int i=0;i<e[mid].size();i++) {
int u=e[mid][i];
memset(maxd,0,sizeof(maxd));
maxd[1]=2;
dep[u]=dep[mid]=2;
fa[u]=mid;fa[mid]=u;
dfs2(u);
dfs2(mid);
s=1;
for(int j=1;j<=len;j++) s*=maxd[j];
ans=min(ans,s);
}
printf("%lld\n",ans);
}
else {
int u=rt2;
for(int i=1;i<len;i++) u=fa[u];
int v=fa[u];
memset(maxd,0,sizeof(maxd));
maxd[1]=2;
dep[u]=dep[v]=2;
fa[u]=v;fa[v]=u;
dfs2(u);
dfs2(v);
ll ans=1;
for(int j=1;j<=len;j++) ans*=maxd[j];
printf("%lld\n",ans);
}
return 0;
}