码迷,mamicode.com
首页 > Web开发 > 详细

UVA 10253 Seris-Parallel Networks

时间:2020-04-06 21:04:12      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:方法   using   一起   还需   它的   端点   pac   while   div   

https://vjudge.net/problem/UVA-10253

题目

串并联网络有两个端点,一个叫源,一个叫汇,递归定义如下。

(1)一条单独的边是串并联网络。

(2)若G1和G2是串并联网络,把他们的源和汇分别接在一起也能得到串并联网络。

(3)若G1和G2是串并联网络,把G1的汇和G2的源并在一起也能得到串并联网络。

其中规则2说的是并联,规则3说的是串联。

串联的各部分可以改变顺序,并联的各部分可以改变顺序,都看作一种串并联网络。

输入n,输出有多少个n条边的串并联网络。$1\leqslant n\leqslant 30$

题解

每个串并联网络都可以看成一棵树,每次串并联都生成一个节点,串并联的部分是它的儿子,叶子是单独的边

所以问题可以转换为n个叶子能得到多少种树,兄弟顺序无关,每个节点要么没有儿子,要么大于两个儿子

那么可以用背包,划分第一层

dp[i][j]表示有i个叶子,现在划分有j个叶子的子树,有多少种方法

f(x)表示含x个叶子的树有多少种,$f(x)=dp[x][x-1]$,因为每个节点要么没有儿子,要么大于两个儿子

$dp[i][j]=\sum dp[i-j*n][j-1]\times C(f(j)+n-1,n)$

得到树以后还需要指定第一层是串联还是并联

还有一些边界情况

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define REPE(i,a,b) for(int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(int i=(a); i>=(b); i--)
using namespace std;
typedef long long ll;
ll dp[37][37],f[37];
ll C(ll n, ll m) {
	double ans=1;
	REP(i,0,m) {
		ans*=n-i;
	}
	REPE(i,1,m) {
		ans/=i;
	}
	return ll(ans+0.5);
}
int main() {
	REPE(i,0,30) dp[0][i]=1;
	REPE(i,1,30) dp[i][0]=0,dp[1][i]=1;
	f[1]=1;

	REPE(j,1,30) {
		REPE(i,2,30) {
			dp[i][j]=0;
			for(int n=0; n*j<=i; n++) {
				dp[i][j]+=dp[i-j*n][j-1]*C(f[j]+n-1,n);
			}
		}
		f[j+1]=dp[j+1][j];
	}
	int N;
	while(~scanf("%d", &N) && N) {
		printf("%lld\n", N==1?1:f[N]*2);
	}
}

 

UVA 10253 Seris-Parallel Networks

标签:方法   using   一起   还需   它的   端点   pac   while   div   

原文地址:https://www.cnblogs.com/sahdsg/p/12643693.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!