定义一棵树上两个点等价当且仅当以这两个点为根的有根树同构,一棵树的权值定义为这棵树的等价类个数。
给出一棵 \(n\) 个点的树,可以在这棵树基础不断的加叶子,使得最后树的权值最小,求出这个权值,以及满足之前条件的所有树中最小叶子数。
数据范围 \(n\le 100\)。
我们发现其实最终所得的树只有两种,一种是以一条边为中心,左右两边同构,一种是以点为中心,呈放射状分布。
其实这两种都一样,以边为放射状的只要把这条边看成一个点就可以了。
这样我们考虑枚举中心,要求其权值,首先不难发现同构的数量其实就是以中心为根的树的深度。然后我们考虑叶子个数,我们只要想想构造这棵树的过程,其实就是把每一层深度的所有点的儿子数补成相同,那么补完后树的叶子个数就是每层非叶子节点儿子个数的乘积,对于原树来讲就是每层儿子树最多的儿子个数的乘积。
复杂度 \(\mathcal{O}(n^2)\),开 \(100\) 大概是为了不爆 long long。
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <map>
#include <set>
#include <stack>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
inline char gc() {
static const int L = 233333;
static char sxd[L], *sss = sxd, *ttt = sxd;
if (sss == ttt) {
ttt = (sss = sxd) + fread(sxd, 1, L, stdin);
if (sss == ttt) {
return EOF;
}
}
return *sss++;
}
#ifndef _AT_HOME
#define dd c = gc()
#else
#define dd c = getchar()
#endif
inline char readalpha() {
char dd;
for (; !isalpha(c); dd);
return c;
}
inline char readchar() {
char dd;
for (; c == ' '; dd);
return c;
}
template <class T>
inline bool read(T& x) {
bool flg = false;
char dd;
x = 0;
for (; !isdigit(c); dd) {
if (c == '-') {
flg = true;
} else if(c == EOF) {
return false;
}
}
for (; isdigit(c); dd) {
x = (x * 10) + (c ^ 48);
}
if (flg) {
x = -x;
}
return true;
}
#undef dd
template <class T>
inline void write(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x < 10) {
putchar(x | 48);
return;
}
write(x / 10);
putchar((x % 10) | 48);
}
template <class T>
inline void writesp(T x) {
write(x);
putchar(' ');
}
template <class T>
inline void writeln(T x) {
write(x);
puts("");
}
#define lowbit(x) (x & -x)
namespace dfcmd {
const int maxn = 105;
typedef long long LL;
int n;
pair<int, LL> ans;
struct Edge {
int to, nxt;
} e[maxn << 1];
int first[maxn];
int du[maxn];
inline void add_edge(int u, int v) {
static int cnt = 0;
du[u]++, du[v]++;
e[++cnt].nxt = first[u];
first[u] = cnt;
e[cnt].to = v;
e[++cnt].nxt = first[v];
first[v] = cnt;
e[cnt].to = u;
}
struct EDGE {
int u, v;
} ee[maxn];
int dep[maxn];
inline void dfs(int now, int fa, int u, int v) {
for (int i = first[now]; i; i = e[i].nxt) {
int to = e[i].to;
if (to != fa && !(now == u && to == v) && !(now == v && to == u)) {
dep[to] = dep[now] + 1;
dfs(to, now, u, v);
}
}
}
int mxx[maxn];
int Main() {
read(n);
for (int i = 1; i < n; ++i) {
read(ee[i].u), read(ee[i].v);
add_edge(ee[i].u, ee[i].v);
}
ans = make_pair(1e9, 1e18);
for (int i = 1; i <= n; ++i) {
dep[i] = 1;
dfs(i, 0, 0, 0);
pair<int, LL> anss(0, 1);
memset(mxx, 0, sizeof(mxx));
for (int i = 1; i <= n; ++i) {
anss.first = max(dep[i], anss.first);
mxx[dep[i]] = max(mxx[dep[i]], du[i]);
}
anss.second = mxx[1];
for (int i = 2; i < anss.first; ++i) {
anss.second *= mxx[i] - 1;
}
ans = min(anss, ans);
}
int tt = n + 1;
du[tt] = 2;
add_edge(tt, 0);
add_edge(tt, 0);
for (int i = 1, nn = n << 1; i < n; ++i) {
e[nn - 1].to = ee[i].u;
e[nn + 1].to = ee[i].v;
dep[tt] = 0;
dfs(tt, 0, ee[i].u, ee[i].v);
pair<int, LL> anss(0, 2);
memset(mxx, 0, sizeof(mxx));
for (int i = 1; i <= n; ++i) {
anss.first = max(dep[i], anss.first);
mxx[dep[i]] = max(mxx[dep[i]], du[i]);
}
for (int i = 1; i < anss.first; ++i) {
anss.second *= mxx[i] - 1;
}
ans = min(anss, ans);
}
writesp(ans.first), writeln(ans.second);
return 0;
}
}
int main() {
return dfcmd::Main();
}