题目描述
树的节点有黑色和白色两种,黑色节点的所有子结点都为黑色。
要求构造一棵初始节点没有颜色的树,对树进行所有满足以上条件的涂色方式共有 种。
输入格式
输入 。
输出格式
第一行输出一个数字 ,代表节点数。
接下来 行,输入两个数字 代表一条连接节点 和节点 的边。
题目分析
这是一道 构造题。
首先对于每个节点,他有黑色和白色两种状态,若其为黑色,则其子节点只能为黑色。
我们列举样例进行分析,首先对于每个叶节点,我们给其赋初值 ,给其他节点赋初值 。一个节点的最终权值为其自身权值加上其直接子节点的权值的乘积,一棵树的权值为其根节点的权值。每个节点的权值也就是以这个节点为根的满足条件的涂色方式。
现在我们要进行上述涂色方式的逆过程,首先我们创造根节点并判断是否还需要继续向下拓展。若其需要继续向下,则 并进入下一层 。对于当前层,若 可以被 整除,则需要添加一个当前层的叶节点,然后 。知道 为奇数为止,若 为 ,则证明构造完毕,否则 并创造一个新节点,以这个新节点为下一层的根节点,进入下一层。依次向下直至构造完毕。
可以大致判断最终层数不超过 。时间复杂度为 。
Accept 代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int k; cin >> k;
vector<int> h(100);
h[1] = 1, k --;
int u = 2, m = 0, n = 1;
while (k > 1)
{
if (k % 2 == 0) m ++, k /= 2;
else
{
k --;
m ++;
h[u ++] = m;
n += m;
m = 0;
}
if (k == 1) h[u ++] = m, n += m;
}
cout << n << "\n";
int root = 1;
for (int i = 2; i < u; i ++)
{
for (int j = 1; j <= h[i]; j ++)
cout << root << ' ' << root + j << "\n";
root += h[i];
}
return 0;
}