// Complete Tree Labeling (完全树标号)
// PC/UVa IDs: 110605/10247, Popularity: C, Success rate: average Level: 2
// Verdict: Accepted
// Submission Date: 2011-06-06
// UVa Run Time: 0.172s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// 如何得到递推关系?设 T(K,D)表示分支因子为 K,深度为 D 的 K 叉树标号的方案数。又设
// N(K,D)表示分支因子为 K,深度为 D 的完全 K 叉树所包含的节点数。根据完全 K 叉树的定义,
// 深度为 D 的完全 K 叉树包含了 K 个深度为 (D - 1) 的完全 K 叉数,其包含的节点数可以
// 表示为 N(K,D - 1),有 K * N(K,D - 1) + 1 = N(K,D)。每个子树的标号方案数为
// T(K,D - 1),则问题转化为下面的问题:N(K,D) - 1 个节点,编号为 1 - (N(K,D) - 1),
// 划分为 K 个子集,每个子集有 N(K,D - 1)个节点,这种划分方法有多少?因为只要确定了划分
// 方法数,则由于知道了 T(K,D - 1),只要将每种划分方法得到的子集和每棵子树一一对应,每个
// 子集的元素可以与 T(K,D - 1) 中的标号形成一一映射,设总的划分方法数为X,则有以下关系:
//
// T(K,D) = X * (T(K,D - 1) ^ K)    (1)
//
// 而集合的划分种数 X 相当与每次从 N(K,D) - 1 个节点中取 N(K,D - 1)个节点,共取 K 次
// 所能得到的不同取法总数。设 A = (N(K,D) - 1),B = N(K,D - 1),A = K * B,有:
//
// X = C(A,B) * C(A - B,B) * …… * C(A - T * B,B),0 <= T <= K - 1 (2)
//
// 根据组合数的定义可将(2)式化简为:
//
// X = (A!) / ((B!) ^ K )  (3)
//
// 最终有:
//
// T(K,D) = (((N(K,D) - 1)! / ((N(K,D - 1)!) ^ K)) * T(K,D - 1)
// ^ K (4)
//
// 容易知道 T(K,0) = 1,N(K,D) = (K ^ (D + 1) - 1) / (K - 1)。则可进一步化简得
// 到:
//
// T(K,D) = (N(K,D) - 1)! / N(K,D - 1) ^ K / N(K,D - 2) ^ (K ^ 2) /.../
// N(K,1) ^ (K ^ (D - 1)) (5)
//
// 可以看出涉及到大数的乘以及除运算。#include <iostream>
#include <vector>
#include <iomanip>
#include <algorithm>using namespace std;class integer
{friend ostream& operator<<(ostream&, const integer&);public:integer() { };// 将无符号整数转换为大整数。integer(unsigned int a){if (a == 0)digits.push_back(0);else{while (a){digits.push_back(a % base);a /= base;}}};~integer() { };integer operator*(const integer&);integer& operator*=(unsigned int);integer& operator*=(const integer&);integer operator/(integer&);bool is_zero(void){return digits.empty();};private:void zero_justify(void);bool less_equal(integer&, unsigned int &, integer&);vector < unsigned int > digits;        // 数位。static unsigned int const base = 10000;  // 基数。static unsigned int const width = 4; // 数位宽度。
};// 重载输出符号 <<。
ostream& operator<<(ostream& os, const integer& number)
{os << number.digits[number.digits.size() - 1];for (int i = number.digits.size() - 2; i >= 0; i--)os << setw(number.width) << setfill('0') << number.digits[i];return os;
}// 移除大数运算产生的前导 0。
void integer::zero_justify(void)
{for (int i = digits.size() - 1; i >= 1; i--){if (digits[i] == 0)digits.erase(digits.begin() + i);elsebreak;}
}integer& integer::operator*=(const integer& b)
{return *this = *this * b;
}// 大数乘以无符号整数。
integer& integer::operator*=(unsigned int b)
{if (b >= base){*this *= integer(b);return *this;}unsigned int carry = 0;for (int i = 0; i < digits.size(); i++){digits[i] = digits[i] * b + carry;carry = digits[i] / base;digits[i] %= base;}if (carry)digits.push_back(carry);return *this;
}// 乘法。
integer integer::operator*(const integer& b)
{integer c;// 预先分配足够空间。c.digits.resize(digits.size() + b.digits.size());fill(c.digits.begin(), c.digits.end(), 0);// 一行一行算,逐行相加。for (int i = 0; i < b.digits.size(); i++)for (int j = 0; j < digits.size(); j++){c.digits[i + j] += digits[j] * b.digits[i];c.digits[i + j + 1] += c.digits[i + j] / base;c.digits[i + j] %= base;}// 去掉前导0。c.zero_justify();return c;
}// 判断 b * v <= row 是否成立,成立返回 true,否则返回 false。
bool integer::less_equal(integer& b, unsigned int &v, integer& row)
{// 由于本题中存在关系 row.digits.size() = b.digits.size() + 1,故可以加以利用。// 若 b * v 的最高位大于 row,则可确定,b * v > row。int carry = b.digits[b.digits.size() - 1] * v;if ((carry / base) > row.digits[row.digits.size() - 1])return false;// 逐位比较,当两个数位不等时,记录比较结果,最后一次的比较结果决定了 b * v 和 row 的大小// 关系。bool flag = true;carry = 0;   for (int i = 0; i < b.digits.size(); i++){int tmp = b.digits[i] * v + carry;carry = tmp / base;tmp %= base;if (row.digits[i] != tmp)flag = tmp < row.digits[i];}// 进位需要与 row 的最高位比较。if (carry != row.digits[row.digits.size() - 1])flag = carry < row.digits[row.digits.size() - 1];return flag;
}// 除法,使用二分法来试除得到商。
integer integer::operator/(integer& b)
{integer c;integer row;// 要为商 c 和表示被减数的 row 分配存储空间。c.digits.resize(digits.size() - b.digits.size() + 1);row.digits.resize(b.digits.size() + 1);// 初始化值。fill(c.digits.begin(), c.digits.end(), 0);fill(row.digits.begin(), row.digits.end(), 0);for (int i = digits.size() - 1; i >= 0; i--){// 获取被除数。for (int j = row.digits.size() - 1; j > 0; j--)row.digits[j] = row.digits[j - 1];row.digits[0] = digits[i];// 通过二分试除法得到对应位的商。int high = base - 1;int low = 0;unsigned int v = (high + low + 1) >> 1;while (high > low){if (less_equal(b, v, row))low = v;elsehigh = v - 1;v = (high + low + 1) >> 1;}// 从 row 中减去 v 个 b。int borrow, start = 0;for (; start < b.digits.size(); start++){// 决定借位的数量。int t = row.digits[start] - v * b.digits[start];if (t < 0)borrow = (base - 1 - t) / base;elseborrow = 0;// 高位减去借位数量。row.digits[start + 1] -= borrow;// 低位加上借位。t += base * borrow;row.digits[start] = t % base;}// 将对应位的商存入结果中。for (int j = c.digits.size() - 1; j > 0; j--)c.digits[j] = c.digits[j - 1];c.digits[0] = v;}// 清除前导 0。c.zero_justify();return c;
}#define TREEDEEPTH 22// 计算分支因子为 k,深度为 d 的标号方案数。
void cal_tree(vector < int > kd)
{// 存储分支因子为 k,深度为 d 的 k 叉数的完全数标号方案数。integer tree[TREEDEEPTH][TREEDEEPTH];// 存储分支因子为 k,深度为 d 的 k 叉数的节点数。unsigned int nodes[TREEDEEPTH][TREEDEEPTH];// 计算满足 k * d <= 21 的树的节点数。并找到最大的节点数。unsigned int max = 0;for (int i = 0; i < kd.size(); i += 2){nodes[kd[i]][0] = 1;for (int j = 1; j <= kd[i + 1]; j++){nodes[kd[i]][j] = nodes[kd[i]][j - 1] * kd[i] + 1;if (nodes[kd[i]][j] > max)max = nodes[kd[i]][j];}}// 计算 1 到节点数 max - 1 的阶乘。vector < integer > fact(max);fact[0] = integer(1);for (unsigned int i = 1; i < max; i++)fact[i] = fact[i - 1] * i;// 根据化简的公式(5)计算标号方案数。for (int i = 0; i < kd.size(); i += 2){   if (tree[kd[i]][kd[i + 1]].is_zero()){// 计算 N(K,M) ^ (K ^ (D - M)),v = K ^ (D - M)。unsigned int v = 1;integer t(1);for (int d = kd[i + 1]; d > 0; d--){v *= kd[i];for (int k = 1; k <= v; k++)t *= nodes[kd[i]][d - 1];}tree[kd[i]][kd[i + 1]] =fact[nodes[kd[i]][kd[i + 1]] - 1] / t;}cout << tree[kd[i]][kd[i + 1]] << endl;}
}int main(int ac, char *av[])
{int k, d;vector < int > kd;while (cin >> k >> d){kd.push_back(k);kd.push_back(d);}cal_tree(kd);return 0;
}

UVa Problem 10247 Complete Tree Labeling (完全树标号)相关推荐

  1. UVA 1264 - Binary Search Tree(BST+计数)

    UVA 1264 - Binary Search Tree 题目链接 题意:给定一个序列,插入二叉排序树,问有多少中序列插入后和这个树是同样的(包含原序列) 思路:先建树,然后dfs一遍,对于一个子树 ...

  2. UVa Problem 123 - Searching Quickly

    // UVa Problem 123 - Searching Quickly // Verdict: Accepted // Submission Date: 2012-01-04 // UVa Ru ...

  3. 【LeetCode】222. Count Complete Tree Nodes 解题报告(Python)

    [LeetCode]222. Count Complete Tree Nodes 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个 ...

  4. UVa Problem 109 - SCUD Busters

    // UVa Problem 109 - SCUD Busters // Verdict: Accepted // Submission Date: 2011-11-24 // UVa Run Tim ...

  5. 222. Count Complete Tree Nodes

    题目: Given a complete binary tree, count the number of nodes. Definition of a complete binary tree fr ...

  6. leetcode 222 Count Complete Tree Nodes

    今天做了一道leetcode题,刚开始是暴力破解,发现special judge, very large tree 过不去,然后一顿想,一顿查,发现可以运用complete binary tree 的 ...

  7. 222 Count Complete Tree Nodes

    1,这道题如果纯用递归数点而不利用其为一个complete binary tree的话会超时. 2.为了利用这个条件,比较左右两子数的高度:1, 如果相等则左子树为完全二叉树 2, 如果不等, 则右子 ...

  8. Middle-题目95:222. Count Complete Tree Nodes

    题目原文: Given a complete binary tree, count the number of nodes. 题目大意: 给出一个完全二叉树,求节点数. 题目分析: 如果直接递归数节点 ...

  9. Count Complete Tree Nodes

    https://leetcode.com/problems/count-complete-tree-nodes/ 宽度优先搜索方法,超时!! /*** Definition for a binary ...

  10. UVa Problem 10310 Dog and Gopher (狗拿地鼠)

    // Dog and Gopher (狗拿地鼠) // PC/UVa IDs: 111301/10310, Popularity: A, Success rate: average Level: 1 ...

最新文章

  1. Android第四十一天(3)
  2. 幸福的2016-----年终总结
  3. em算法 实例 正态分布_EM算法解GMM
  4. 述职答辩提问环节一般可以问些什么_论文答辩一般会问什么问题?需要注意什么事项?...
  5. 2019年中国高校社会影响力排行榜出炉!有你母校吗?
  6. 文件共享存储主备实时热备实现方案
  7. 人月神话:微软开发模式和原则[转]
  8. 5.5.35 - mysql 同步_MySQL 5.6.35主从同步配置案例
  9. C# ref,out
  10. Docker Compose 笔记
  11. 深入理解机械臂动力学建模
  12. 符号执行技术总结(A Brief Summary of Symbol Execution)- wcventure
  13. 惠普台式计算机系列,惠普星系列590-051 台式机 拆解
  14. 电动汽车(EV)无线充电(WPT)及标准
  15. 【立青】安装python及各种数据包
  16. 端午节谋定顺应自然-农业大健康·万祥军:根植古代农耕文化
  17. EOS的trace_api_plugin插件测试
  18. php 领红包程序,用PHP实现的抢红包小程序
  19. 在windows和Deepin上安装Fedora33-KDE:一波三折、第九次成功的嘤嘤怪
  20. dcloud进行android离线打包 需要继承io.dcloud.application.DCloudApplication的问题

热门文章

  1. go语言调用c 的头文件 so,golang 学习(10): 使用go语言调用c语言的so动态库-Go语言中文社区...
  2. html实现文字在表格上方左侧,html,表格,左对齐.doc
  3. hugo搭建个人博客
  4. greenDao的使用教程
  5. 【论文解读 KDD 2018 | HEER】Easing Embedding Learning by Comprehensive Transcription of HIN
  6. vscode超好玩好用的插件
  7. GPIO输入输出各种模式(推挽、开漏、准双向端口)详解
  8. 计算机丢失drivers文件,system32\drivers.Sys文件丢失怎么解决?
  9. 浅谈智能卡技术在数字电视小额支付系统中的应用
  10. Win10(Win7)局域网设置共享文件夹,超全面步骤。