标签:方法 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)$
得到树以后还需要指定第一层是串联还是并联
还有一些边界情况
#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