出题人题解。

C 兜心の顶

按道理边做这题边点开 P7238、P7807,应该通过率 100% 吧。

下文中「唯一性」代指直径、重心、直径重心三个「唯一」,「不等性」代指树的重心不等于直径重心。

一、直径的长度讨论

首先直径 不会是偶数

否则设直径的长度是 \(2k\),由 \(1\cdots 2k\)\(2k\) 个结点组成。

那么结点 \(k\) 和结点 \(k+1\) 必然都是直径重心,与唯一性不符,舍去。

然后直径不可能是 \(1\):显然。

直径不可能是 \(3,5\):此时重心只能出现在中间的点(否则与唯一性不符),与不等性不符。

综上,直径长度至少为 \(7\) 且必为奇数。

二、重心位置的讨论

不妨钦定我们构造的树的直径就是 \(7\),下面来看看位置:

首先直径的重心一定是 \(1\cdots7\) 号结点的中点:\(4\) 号结点。

那么树的重心一定要出现在其他结点上,首先 \(1,2,6,7\) 被排除,理由是唯一性。

那么只剩下 \(3,5\) 两个对称的结点,我们不妨设重心是 \(3\) 号结点。

此时需要给 \(3\) 号结点再安排上一些子树,为了不影响唯一性,\(3\) 的其他子树深度只能为 \(1\)

那么考虑到 \(3\) 必须是唯一重心,至少要加入两个新结点,才能保证。

综上,树的大小至少为 \(9\),且形态为:

\[1\leftrightarrow2\leftrightarrow\color{red}3\color{black}\leftrightarrow\color{blue}4\color{black}\leftrightarrow5\leftrightarrow6\leftrightarrow7 \]
\[8\leftrightarrow\color{red}3\color{black}\leftrightarrow9 \]

其中 \(\color{red}3\) 是树的重心,\(\color{blue}4\) 是直径重心,上面的这一条链就是直径。

三、N >= 10 情况的讨论

不难发现,只要我们继续按照该策略,不断地给结点 \(3\) 添加新的子结点(形成一张菊花图)即可。

四、代码实现

\(N\le8\) 时:输出 -1

其他情况,先输出

\[1\leftrightarrow2\leftrightarrow\color{red}3\color{black}\leftrightarrow\color{blue}4\color{black}\leftrightarrow5\leftrightarrow6\leftrightarrow7 \]

这个基本模型,然后对于 \(i=8\sim N\) 的所有结点 \(i\),全部连向结点 \(3\) 即可。

std

#include<cstdio>
int init(){
	char c = getchar();
	int x = 0, f = 1;
	for (; c < '0' || c > '9'; c = getchar())
		if (c == '-') f = -1;
	for (; c >= '0' && c <= '9'; c = getchar())
		x = (x << 1) + (x << 3) + (c ^ 48);
	return x * f;
}
int print(int x){
	if (x < 0) x = -x, putchar('-');
	if (x > 9) print(x / 10);
	putchar(x % 10 + '0');
	return 0;
}
int main(){
	int n = init();
	if (n <= 8) return print(-1);
	print(n), putchar('\n');
	for (int i = 1; i <= 6; ++i)
		print(i), putchar(' '), print(i+1), putchar('\n');
	for (int i = 8; i <= n; ++i)
		print(3), putchar(' '), print(i), putchar('\n');
}

五、后记

本题显然有很多合理的构造,但是我发现本构造最为清晰、整洁、易懂。