Series-Parallel Networks UVA 10253

训练指南写如果一个节点表示并联(串联)则其子节点全部为串联(并联)或者单边这是因为任何一个并联(串联)网络都可以由若干个个串联(并联)网络并联(串联)起来组成,这样计数就保证既无重复,有无遗漏,这道题实际上求的是有n个叶节点而且每个非叶节点有至少俩棵子树的树的个数而且注意子树之间是无序的。

整数划分版本:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string> 
#include <sstream>
#include <utility>   
#include <ctime>
 
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
using std::endl;

typedef long long LL;

int vec[50];
LL table[50];

LL C(LL n, LL m)
{
	double ret = 1.;
	for(int i = 0; i < m; ++i)
		ret *= n-i;
	for(int i = m; i >= 1; --i)
		ret /= i;
	return LL(ret+0.5);
}

void dfs(int s, int res, int n)
{
	if(res == 0)                            
	{
		LL temp = 1LL;
		for(int i = 1; i <= n-1; ++i)
			temp *= C(table[i]+vec[i]-1, vec[i]);
		table[n] += temp;
		return;
	}
	int lim = min(res, n-1);
	for(int i = s; i <= lim; ++i)
	{
		++vec[i];
		dfs(i, res-i, n);
		--vec[i];
	}
}
        
int main()
{
	table[1] = 1LL;
	for(int i = 2; i <= 30; ++i)
		dfs(1, i, i);
	int n;
	while(scanf("%d", &n), n)
	{
		printf("%lld\n", n == 1? 1LL: table[n]*2LL);
	}
	return 0;
}


递推版本:其中table[i][j]表示有i个叶子节点且根的子树最多有j个叶子节点的树的个数

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string> 
#include <sstream>
#include <utility>   
#include <ctime>
 
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
using std::endl;

typedef long long LL;

LL C(LL n, LL m)
{
	double ret = 1.;
	for(int i = 0; i < m; ++i)
		ret *= n-i;
	for(int i = m; i >= 1; --i)
		ret /= i;
	return LL(ret+0.5);
}

LL table[50][50];

inline LL fun(int ind)
{
	return table[ind][ind-1];
}

int main()
{
	for(int i = 1; i <= 30; ++i)
	{
		table[i][0] = 0LL;
		table[0][i] = 1LL;
		table[i][1] = 1LL;
	}
	table[0][0] = 1LL;
	for(int i = 1; i <= 30; ++i)
	{
		for(int j = 2; j <= 30; ++j)
			for(int p = 0; p*j <= i; ++p)
				table[i][j] += C(fun(j)+p-1, p)*table[i-j*p][j-1];
	}
	int n;
	while(scanf("%d", &n), n)
	{
		printf("%lld\n", n == 1? 1: fun(n)*2);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值