让我们创建一个稍大的树,如下所示。
1
/ | \
2 3 \
/ 4
7 / \
5 6
让我们为每个节点 'a' 定义一个函数 F(a, k),并从节点 'a' 及以下移除 'k' 条边。
即,如果从节点“a”中删除“k”条边,那么我们创建 F(a,k) 个子树。
(如果 'a' 不是根,则假定它连接到它的父级)。
例如在上面的树( F(4, 1) = 2 )中,我们通过删除 '4' 下面的 2 条边来创建 2 棵树
(我们假设 4 与父节点相连,子树 (5) 和 (6) 不计入 F(4,1))
我们首先遍历并计算每个孩子的'F'。然后使用孩子的 F 我们计算
父母 F.
叶子节点的F(a, k)对于所有k都是'0'
对于非叶节点。
F(a, k) = SUM (F(child, k)) + Z
而 F(child, k) 可以递归计算。
另一方面,Z 是通过查找某个孩子选择的所有组合来计算的
ri 超出 k 的边缘,使得 SUM(ri) = k
这可以通过为给定的孩子修复“j”边缘来以编程方式完成,然后
计算通过将“k-j”条边分配给其他孩子创建的树的数量。
例如在上面的树中
F(1, 3) = F(2, 3) + F(3, 3) + F(4, 3) + // we pass k as-is to child
F(2,1)*F(3,1)*F(4,1) + F(2,1)*F(3,2) + F(2,1)*F(4,2) + //consume 1 edge by 2 and distribute 2 to other children
F(2, 2)*F(3,1) + F(2,2)*F(4,1) + // consume 2 edges from node '2' and 1 for other children
F(3,1)*F(4,2)
正如我们在上面看到的,我们为节点 2 固定“r”边,然后将“3-r”边分配给其他子节点。
我们继续为“1”的所有孩子这样做。
此外,当我们从父节点分离节点时,我们会创建子树。
例如在上述情况下,当我们计算 F(1, 3) 时,我们创建以下
分离的树木。
分离树 += F(2, 2) + F(3, 2) + F(4, 2)
在这里,我们假设通过将子节点与父节点分离来消耗一条边,
在子节点中,如果我们消耗“k-1”条边,我们将创建 F(child, k-1) 子树。
这些树被计数并单独存储在 detached_trees 中。
一旦我们计算了所有节点的 F(a,k)。
总的子树是 'SUM(F(root, k)) for all k' + 'total nodes - 1' + detached_trees。
我们将“节点总数 - 1”添加到总数中。这是因为当一个节点(根除外)被分离时
从一棵树中,它会创建两棵缺少 1 条边的树。当一棵树被计算在内时
在 F(parent, 1) 中,另一个不在任何地方计算,因此需要总计计算。
这是上述算法的 C 代码。递归可以进一步优化。
#define MAX 51
/* We use the last entry of alist to store number of children of a given node */
#define NUM_CHILD(alist, node) (alist[node][MAX])
int alist[MAX][MAX+1] = {0};
long F[MAX][MAX]={0};
long detached_subtrees = 0;
/*
* We fix one of the child node for 'i' edges out of 'n', then we traverse
* over the rest of the children to get 'n-i' edges, we do so recursivly.
* Note that if 'n' is 1, we can always build a subtree by detaching.
*/
long REST_OF_NODES_SUM(int node, int q, int n)
{
long sum = 0, i, node2, ret = 0, nd;
/* fix node2 and calcualte the subtree for rest of the children */
for(nd = q; nd < NUM_CHILD(alist, node); nd++) {
node2 = alist[node][nd];
/* Consume 'i' edges and send 'n-i' for other children of node */
for (i = 1; i < n ; i++) {
sum = REST_OF_NODES_SUM(node, nd + 1, n - i);
ret += (F[node2][i] * sum);
/* Add one for 'node2' getting detached from tree */
if (i == 1) { ret += sum; }
}
ret += F[node2][n];
/* If only one edge is to be consumed, we detach 'node2' from the tree */
if (n == 1) { ret++; }
}
return ret;
}
void get_counts(int N, int K, int node, int root)
{
int child_node;
int i, j, p, k;
if (NUM_CHILD(alist, node) == 0) { return; }
for(i = 0 ; i < NUM_CHILD(alist, node); i++) {
child_node = alist[node][i];
/* Do a recursive traversal of all children */
get_counts(N, K, child_node, node);
F[node][1] += (F[child_node][1]);
}
F[node][1] += NUM_CHILD(alist, node);
for (k = 2; k <= K; k++) {
for(p = 0; p < NUM_CHILD(alist, node); p++) {
child_node = alist[node][p];
F[node][k] += F[child_node][k];
/* If we remove this child, then we create subtrees in the child */
detached_subtrees += F[child_node][k-1];
/* Assume that 'child_node' is detached, find tree created by rest
* of children for 'k-j' edges */
F[node][k] += REST_OF_NODES_SUM(node, p + 1, k - 1);
/* Fix one child node for 'j' edges out of 'k' and traverse over the rest of
* children for 'k - j' edges */
for (j = 1; j < k ; j++) {
if (F[child_node][j]) F[node][k] += (F[child_node][j] * REST_OF_NODES_SUM(node, p + 1, k - j));
}
}
}
}
void remove_back_ref(int parent, int node)
{
int c;
for (c = 0; c < NUM_CHILD(alist, node); c++) {
if (alist[node][c] == parent) {
if ((c + 1) == NUM_CHILD(alist, node)) {
NUM_CHILD(alist, node)--;
alist[node][c] = 0;
} else {
/* move last entry here */
alist[node][c] = alist[node][NUM_CHILD(alist, node)-1];
alist[node][NUM_CHILD(alist, node)-1] = 0;
NUM_CHILD(alist, node)--;
}
}
}
}
/* go to each child and remove back links */
void normalize(int node)
{
int j, child;
for (j = 0; j < NUM_CHILD(alist, node); j++) {
child = alist[node][j];
remove_back_ref(node, child);
normalize(child);
}
}
long cutTree(int N, int K, int edges_rows, int edges_columns, int** edges)
{
int i, j;
int node, index;
long ret = 0;
/* build an adjacency list from the above edges */
for (i = 0; i < edges_rows; i++) {
alist[edges[i][0]][NUM_CHILD(alist, edges[i][0])] = edges[i][1];
alist[edges[i][1]][NUM_CHILD(alist, edges[i][1])] = edges[i][0];
NUM_CHILD(alist, edges[i][0])++;
NUM_CHILD(alist, edges[i][1])++;
}
/* get rid of the back links in children */
normalize(1);
get_counts(N, K, 1, 1);
for (i = 1; i <= K; i++) { ret += F[1][i]; }
/* Every node (except root) when detached from tree, will create one extra subtree. */
ret += (N - 1);
/* The subtrees created by detaching from parent */
ret += detached_subtrees;
/* Add two for empty and full tree */
ret += 2;
return ret;
}
main(int argc, char *argv[])
{
int **arr;
int ret, i, N, K, x, y;
scanf("%d%d", &N, &K);
arr = malloc((N - 1) * sizeof(int*));
for (i = 0; i < (N - 1); i++) { arr[i] = malloc(2*sizeof(int)); }
for (i = 0; i < N-1; i++) { scanf("%d%d", &x, &y); arr[i][0] = x; arr[i][1] = y; }
printf("MAX %d ret %ld\n", MAX, cutTree(N, K, N-1, 2, arr));
}