蓝书例题之UVa 10253 Series-Parallel Networks

挺有趣的一道题
首先转化模型,思路参考蓝书,可得出等同于求共n个叶子,且每个非叶结点至少有两个子结点的无标号树的个数的二倍,设个数为\(f[n]\)
考虑怎么求\(f[n]\),假设有一个\(n\)的整数划分,分别代表每棵子树中的叶节点个数,然后用可重组合,乘法原理和加法原理把\(f[n]\)递推出来
这个过程可以用\(dp\)来完成,设\(g[i][j]\)表示子树中叶结点数量最大值小于等于\(i\),共有\(j\)个叶结点的树的个数,转移时枚举最大的叶结点数量\(i\)和叶结点数量为\(i\)的子树个数\(k\),转移方程如下:
\[g[i][j]=\sum\limits_{k=0}^{ki\leqslant j}\binom{f[i]+k-1}{k}g[i-1][j-ki]\]
然后\(f[i]=g[i-1][i]\)
边界的设置比较神奇,我也不明白,直接把大刘的代码拿过来用了

#include <bits/stdc++.h>

using namespace std;

#define ll long long
#define N 30

ll C(ll n, ll m) {
  double ans = 1;
  for(ll i = n-m+1; i <= n; ++i) ans *= i;
  for(ll i = 1; i <= m; ++i) ans /= i;
  return (ll)(ans+0.5);
}

ll g[35][35], f[35];

int main() {
  f[1] = 1; //三个边界
  for(int i = 0; i <= N; ++i) g[i][0] = 1;
  for(int i = 1; i <= N; ++i) g[i][1] = 1;
  for(int i = 1; i <= N; ++i) {
    for(int j = 1; j <= N; ++j) {
      g[i][j] = 0;
      for(int k = 0; k*i <= j; ++k) g[i][j] += C(f[i]+k-1, k)*g[i-1][j-k*i];
    }
    f[i+1] = g[i][i+1];
  }
  int n;
  while(~scanf("%d", &n) && n) printf("%lld\n", n == 1 ? 1 : 2*f[n]); //特判1,别忘乘以2
  return 0;
}

原文地址:https://www.cnblogs.com/dummyummy/p/10686901.html

时间: 2024-10-09 21:28:29

蓝书例题之UVa 10253 Series-Parallel Networks的相关文章

UVA 10253 - Series-Parallel Networks(数论+计数问题+递推)

题目链接:10253 - Series-Parallel Networks 白书的例题. 这题也是需要把问题进行转化,一个并联可以分为几个串联,然后串联可以分成边. 如此一来,最后叶子结点种数会是n,问题转化为去分配叶子结点,使得总和为n. 书上有两种方法,一种直接去递归,利用组合数学的方式去计算答案. 一种是推出递推式: 设dp[i][j]为一共j个叶子结点的树,子树的叶子最多的为i个的情况.然后对于一颗树,枚举恰好包含i个叶子的子树为p棵,那么相当于从f[i]颗树中选出p棵树的方案数,是可重

黑书例题 Fight Club 区间DP

题目可以在bnuoj.soj等OJ上找到. 题意: 不超过40个人站成一圈,只能和两边的人对战.给出任意两人对战的输赢,对于每一个人,输出是否可能是最后的胜者. 分析: 首先序列扩展成2倍,破环成链. dp[i][j]表示i和j能够相遇对打,那么dp[i][i+n]为真代表可以成为最后胜者. 枚举中间的k,若i和j都能和k相遇,且i和j至少一人能打赢k,那么i和j可以相遇. 复杂度o(n^3) 1 #include<cstdio> 2 #include<cstring> 3 usi

【例题 7-11 UVA - 12325】Zombie&#39;s Treasure Chest

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 1.N/s1 < 1e6 枚举1的个数 2.N/s2<1e6 枚举2的个数 3.s1和s2的值较小 假设买了s2个1和s1个2 那么这两种物品占的体积就一样大了. 即都为s1s2 而第一种物品价值为s2v1第二种物品价值为s1v2 那么 如果s2v1>s1v2的话. 可以想见,如果第二种物品的数量超过了s1的话,显然可以把它占的体积都用来买物品1,因为那样更优. 则我们第二种物品最多只要枚举到s1就可以了. 同理s2v1

蓝书《哈希与哈希表》——知识整理

一.前言: 有些数据不经处理是难以利用的.所谓哈希,就是通过哈希函数将这种难以简单利用的数据(比如矩阵.字符串等等)转化为可以用一个变量表示甚至可以作为数组下标的哈希值.有了哈希值,就可以实现时间复杂度近乎为常数的快速查找与匹配,更简单有效地利用一些复杂数据. 二.字符串哈希: 即对象为字符串的哈希.常将字符串看做一个不严格的b进制的数(有时数位上的数有可能要比b还要大),转换为10机制后再模一个数p(以便存储)得到哈希值.即定义哈希函数: H(C)=(c1*b^(m-1) + c2*b^(m-

0x46蓝书习题:普通平衡树

Treap/平衡二叉树 蓝书习题:普通平衡树 这道题是一道平衡树模板题,可以用多种解法,这里用最简单的Treap,下面简单说一下各种操作的思路 添加: 当要添加一个值时,先判断所要加入的以p为根节点的子树是否为空,为空添加新的节点:New(val). 当然平衡树,当加入新节点后,子节点dat变得大于a[p].dat时,要旋转,左旋右旋见代码,好理解. void Insert(int &p,int val){ if(!p){ p=New(val); return; } if(val==a[p].v

紫书例题6-3 (UVa 442)

题目地址:https://vjudge.net/problem/UVA-442 题目大意:汗颜,其实我是直接看紫书的中文题意的,大意就是计算两个矩阵乘法次数,设计线性代数知识,可自己百度矩阵乘法. 思路:栈+模拟,左括号开始入栈,右括号开始计算栈顶两个矩阵的乘法次数然后再将新矩阵的n,m入栈即可. AC代码: #include <iostream> #include <string> #include <stack> #include <cstring> u

紫书例题6-4 (UVa 11988)

题目链接:https://vjudge.net/problem/UVA-11988 题目大意:输入一串字符,并按照要求输出,遇到'['字符就将光标移动到开头,遇到']'字符就将光标移动到末尾. 思路: 题目不难懂,很明显的一个模拟就行,重点是如何取存储,这里选择使用链表,链表的具体定义可以去百度看一下,这里不做过多解释,可以简单理解为一个未知长度的数组,它可以借助指针在任意位置插入(删除). 这题具体的操作可以用草稿纸模拟一遍,我是看一位博主的blog明白的,原blog地址:https://bl

la3523 白书例题 圆桌骑士 双联通分量+二分图

具体题解看大白书P316 #include <iostream> #include <algorithm> #include <vector> #include <string.h> #include <stack> #include <cstdio> using namespace std; struct Edge{int u,v;}; const int maxn = 1000+10; int pre[maxn],iscut[ma

UVa 10253 (组合数 递推) Series-Parallel Networks

<训练之南>上的例题难度真心不小,勉强能看懂解析,其思路实在是意想不到. 题目虽然说得千奇百怪,但最终还是要转化成我们熟悉的东西. 经过书上的神分析,最终将所求变为: 共n个叶子,每个非叶节点至少有两个子节点的 树的个数f(n).最终输出2 × f(n) 首先可以枚举一下根节点的子树的叶子个数,对于有i个叶子的子树,共有f(i)种, 设d(i, j)表示每棵子树最多有i个叶节点,一共有j个叶节点的方案数. 所求答案为d(n-1, n) 假设恰好有i个叶子的子树有p棵,因为每个子树互相独立,所以