UVA 10516 - Another Counting Problem(递推)

Problem H
Another Counting Problem
Input: 
Standard Input

Output: Standard Output

Tree is an important data structure in Computer Science. Of all trees we work with, Binary Tree is probably the most popular one. A Binary Tree is called Strictly Binary Tree if every nonleaf node in a binary tree has nonempty left and right subtrees. Let us define a Strictly Binary Tree of depth d, as a Strictly Binary Tree that has at least one root to leaf path of length d, and no root to leaf path in that tree is longer than d. So let us use a similar reasoning to define a generalized structure.

A n-ary Tree is called Strictly n-ary Tree if every nonleaf node in a n-ary tree has n children eacha Strictly n-ary Tree of depth d, then can be defined as a Strictly n-ary Tree that has at least one root to leaf path of length d, and no root to leaf path in that tree is longer than d.

Given the value of n and depth d, your task is to find the number of different strictly n-ary trees of depth d.

The figure below shows the 3 different strictly binary trees of depth 2.

Input

Input consists of several test cases. Each test case consists of two integers n (0 < n <= 32), d (0 <= d <= 16). Input is terminated a test case where n=0 and d=0, you must not process this test case.

 

Output

For each test case, print three integers, n, d and the number of different strictly n-ary trees of level d, in a single line. There will be a single space in between two integers of a line. You can assume that you would not be asked about cases where you had to consider trees that may have more than 210 nodes in a level of the tree. You may also find it useful to know that the answer for each test case will always fit in a 200 digit integer.

 

Sample Input                               Output for Sample Input

2 0
2 1
2 2
2 3
3 5
0 0
2 0 1
2 1 1
2 2 3
2 3 21
3 5 58871587162270592645034001

 

 

题意:n叉高度为d的严格二叉树有几种

思路:递推。dp[i]表示高度不超过i的总数。那么对于n叉树而言,每个子树都有dp[i - 1]种,那么一共就有dp[i - 1] ^ n种,在加上高度为1的一种,dp[i] = dp[i - 1]^n + 1;本来打表的,结果一直跑不出来。后来才发现题目说输出不会超过200位,而如果n <= 32 d <= 16,是有可能位数非常大的!。

代码:

#include <stdio.h>
#include <string.h>
#include <math.h>


#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)

const int MAXSIZE = 1005;

struct bign {
    int s[MAXSIZE];
    bign ()	{memset(s, 0, sizeof(s));}
    bign (int number) {*this = number;}
    bign (const char* number) {*this = number;}

    void put();
    bign mul(int d);
    void del();

    bign operator =  (char *num);
    bign operator =  (int num);

    bool operator <  (const bign& b) const;
    bool operator >  (const bign& b) const { return b < *this; }
    bool operator <= (const bign& b) const { return !(b < *this); }
    bool operator >= (const bign& b) const { return !(*this < b); }
    bool operator != (const bign& b) const { return b < *this || *this < b;}
    bool operator == (const bign& b) const { return !(b != *this); }

    bign operator + (const bign& c);
    bign operator * (const bign& c);
    bign operator - (const bign& c);
    int  operator / (const bign& c);
    bign operator / (int k);
    bign operator % (const bign &c);
    int  operator % (int k);
    void operator ++ ();
    bool operator -- ();
};

bign bign::operator = (char *num) {
    s[0] = strlen(num);
    for (int i = 1; i <= s[0]; i++)
	s[i] = num[s[0] - i] - '0';
    return *this;
}

bign bign::operator = (int num) {
    char str[MAXSIZE];
    sprintf(str, "%d", num);
    return *this = str;
}

bool bign::operator < (const bign& b) const {
    if (s[0] != b.s[0])
	return s[0] < b.s[0];
    for (int i = s[0]; i; i--)
	if (s[i] != b.s[i])
	    return s[i] < b.s[i];
    return false;
}

bign bign::operator + (const bign& c) {
    int sum = 0;
    bign ans;
    ans.s[0] = max(s[0], c.s[0]);

    for (int i = 1; i <= ans.s[0]; i++) {
	if (i <= s[0]) sum += s[i];
	if (i <= c.s[0]) sum += c.s[i];
	ans.s[i] = sum % 10;
	sum /= 10;
    }
    return ans;
}

bign bign::operator * (const bign& c) {
    bign ans;
    ans.s[0] = 0; 

    for (int i = 1; i <= c.s[0]; i++){  
	int g = 0;  

	for (int j = 1; j <= s[0]; j++){  
	    int x = s[j] * c.s[i] + g + ans.s[i + j - 1];  
	    ans.s[i + j - 1] = x % 10;  
	    g = x / 10;  
	}  
	int t = i + s[0] - 1;

	while (g){  
	    ++t;
	    g += ans.s[t];
	    ans.s[t] = g % 10;
	    g = g / 10;  
	}  

	ans.s[0] = max(ans.s[0], t);
    }  
    ans.del();
    return ans;
}

bign bign::operator - (const bign& c) {
    bign ans = *this;
    for (int i = 1; i <= c.s[0]; i++) {
	if (ans.s[i] < c.s[i]) {
	    ans.s[i] += 10;
	    ans.s[i + 1]--;;
	}
	ans.s[i] -= c.s[i];
    }

    for (int i = 1; i <= ans.s[0]; i++) {
	if (ans.s[i] < 0) {
	    ans.s[i] += 10;
	    ans.s[i + 1]--;
	}
    }

    ans.del();
    return ans;
}

int bign::operator / (const bign& c) {
    int ans = 0;
    bign d = *this;
    while (d >= c) {
	d = d - c;
	ans++;
    }
    return ans;
}

bign bign::operator / (int k) {
    bign ans; 
    ans.s[0] = s[0];
    int num = 0;  
    for (int i = s[0]; i; i--) {  
	num = num * 10 + s[i];  
	ans.s[i] = num / k;  
	num = num % k;  
    }  
    ans.del();
    return ans;
}

int bign:: operator % (int k){  
    int sum = 0;  
    for (int i = s[0]; i; i--){  
	sum = sum * 10 + s[i];  
	sum = sum % k;  
    }  
    return sum;  
} 

bign bign::operator % (const bign &c) {
    bign now = *this;
    while (now >= c) {
	now = now - c;
	now.del();
    }
    return now;
}

void bign::operator ++ () {
    s[1]++;
    for (int i = 1; s[i] == 10; i++) {
	s[i] = 0;
	s[i + 1]++;
	s[0] = max(s[0], i + 1);
    }
}

bool bign::operator -- () {
    del();
    if (s[0] == 1 && s[1] == 0) return false;

    int i;
    for (i = 1; s[i] == 0; i++)
	s[i] = 9;
    s[i]--;
    del();
    return true;
}

void bign::put() {
    if (s[0] == 0)
	printf("0");
    else
	for (int i = s[0]; i; i--)
	    printf("%d", s[i]);
}

bign bign::mul(int d) {
    s[0] += d;
    for (int i = s[0]; i > d; i--)
	s[i] = s[i - d];
    for (int i = d; i; i--)
	s[i] = 0;
    return *this;
}

void bign::del() {
    while (s[s[0]] == 0) {
	s[0]--;
	if (s[0] == 0) break;
    }
}


int n, m;
bign dp[17], one = 1;

void solve() {
    dp[0] = 1;
    for (int j = 1; j <= m; j ++) {
	dp[j] = 1;
	for (int k = 0; k < n; k ++) {
	    dp[j] = dp[j] * dp[j - 1];
	}
	dp[j] = dp[j] + one;
    }
    (dp[m] - dp[m - 1]).put();
    printf("\n");
}

int main() {
    while (~scanf("%d%d", &n, &m) && n) {
	printf("%d %d ", n, m);
	if (m == 0) printf("1\n");
	else solve();
    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值