挑战编程第六章 组合数学 读书笔记

第六章  组合数学 读书笔记

1. 全排列的数目是n !,当 n=10 时, n =3628800 ,接近穷举极限。

2. N个元素的子集为 2^n ,非空子集为 2^n-1 ,非空真子集为 2^n-2 ,当 n=20 时, 2^n=1048576 接近穷举极限。

3. 研究若干可重复元素所组成的序列。假设有m 种元素,则有 m^n 个长度为 n 的序列(也就是每个位置上有 m 种取法,共 n 个位置),另外,长度为 n 的二元串(也就是只包含两种不同字符)的个数等于 n 个不同元素的子集数目(每个位置有 2 种取法,所以有 2^n ,根据上一条,显然等于个数为 n 个的不同元素的子集数目)

 

一、 二项式系数

1. n 个人中选出 k 个人答案为 C(n,k)

2. 穿越网格的路径数:从一个n*m 的网格的左上角走到右下角,很显然要走 n+m 步, n 次往下, m 次往右,从中选择 n 步往下,所以是 C(n+m,n) ,同理,也可以从中选择 m 步往右,因此有 C(n+m,m)=C(n+m,n) 可得 C(n,k)=C(n,n-k)

3. 顾名思义,二项式系数即为(a+b)^n 的系数,同样意义为从 n 个因子中选择 k 个因子 a 的方案数,为 C(n,k)

4. 杨辉三角。该表为二项式系数,第(n+1) 行第 i 个数为 C(n,i) 的值。另外,第 (n+1) 行之和为 2^n ,也就是说 C(n,0)+C(n,1)+...+C(n,n)=2^n 。另外很显然在杨辉三角中,一个数是由上两个数相加得到(非边界情况),所以有公式 C(n,k)=C(n-1,k-1)+C(n-1,k) ,有效预防用阶乘相除溢出的情况( ps C(n,k)=n!/[(n-k)!k!] ),然后边界为 C(n,0)=C(n,n)=1 。代码如下(递归函数):

int C(int n,int k)

{

if (n==k || n==0) return 1;

return C(n-1,k)+C(n-1,k-1);

}

同样可以用递推写

for (i=0;i<=n;i++)

{

for (j=0;j<=i;j++)

{

if (j==0 || i==j) c[i][j]=1;

else c[i][j]=c[i-1][j]+c[i-1][j-1];

}

}

二、 斐波那契数列(兔子问题……)

1. 递推公式:Fn=Fn-1+Fn-2,F0=0,F1=1

2. 封闭形式: (误差正负 1

3. 楼梯问题:一段楼梯有n 级台阶,一次只能跨 1-2 级,问有多少种走法。要么跨一级,也就是 Fn-1 种,要么跨两级 Fn-2 种,相加正好为斐波那契数列。

 

三、 Catalan

1. 通项公式 其中, C0=1,前几项为: 2,5,14,42,132,429,1430

2. 递归公式: h(n)= h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) (其中 n>=2)  

3. 括号问题:n 对括号可以构造出多少平衡的括号表达式?平衡的表达式就是说括号互相配对,例如 n=3 ((())) ()(()) (())() (()()) ()()() 五种,假设其中一个括号为 s ,那么与他配对的括号为 t ,则 s t 将表达式分成三个平衡的部分,也就是括号内部,括号左边,括号右边,以右括号为分界线,那么则可以说分成两个平衡部分,括号内部和括号左边合并为一个部分。所以假设右边有 k 个括号,左边有 n-k-1 个括号(因为我们正在用一个括号 s t ),所以有 Cn 通项公式的前半部分。可以将此问题拓展为连乘或连加的加括号种类问题。

4. 出栈次序问题,问1--n 入栈,有多少种出栈情况。很显然第一次可以一次性出栈 1 1.2 .... 1.2..k ,有 h(k) 种情况,之后剩下的就是 h(n-k) 种情况,枚举 k 后可以得到 Catalan 数的递归式。该问题可以推广如下问题:圆上 2n 个点成对连起来,求 n 条线段不想交情况;商店卖 5 元物品, n 个顾客手中有 5 元钞票, n 个顾客有十元钞票,售货员没有任何零钱。问有多少种方法使得只要十元钞票的顾客来买东西,售货员就有五元钱可以找。(可以看做持 5 元的顾客买东西为 5 元入栈,持 10 元顾客买东西为 5 元出栈);一位大城市的市民在他所住地方的东北方(往东 n 个街区,往北 n 个街区)上班,如果他不穿越对角线,有几种走法(同样可以构造往东走为入栈,往北走为出栈)

5. 多边形三角剖分(经典的dp 题!只不过这里只要求剖分情况)一条线可以将多边形剖为两个多边形,之后递归求出两个多边形的剖分情况,最后固定一个点,枚举另一个点确定这一条线的情况数即可。

6. 给出顶点个数问能构造多少二叉树。同样枚举左边和右边子树的顶点个数,之后递归求出左右子树构造二叉树的情况。

 

四、 欧拉数(ps :有很多欧拉数啊,不要搞混了…) F(n,k) 表示 1.2...n 的排列中恰好包含 k 次下降或者包含 k+1 次上升(例如 {3,6,1,4,5,2} 中有两个下降 {6,1}{5,2} ,三个上升 {3,6}{1,4,5},{2} ps :单个数字算上升啊…)的排列个数,那么假设前 n-1 的排列中有 k 次下降,那么现在 n 插入的位置就要插到上升序列的后面(因为 n 最大,上升序列后面必为下降序列,而 n 与后面的下降数列结合还是下降数列,所以不会造成下降数列变多)因此有 k+1 种方法,另外假设前 n-1 的排列有 k-1 个下降,所以要放在上升序列的中间或者整个序列的开头才能保证多一个下降序列,因此有 (n-k) 种方法,递推公式为 F(n,k)=(k+1)F(n-1,k)+(n-k)F(n-1,k-1)

 

五、 第一类Stirling

|S(n,k)| 为包含 n 个元素的集合分做 k 个环的方法数目,而 S(n,k)=S(n-1,k-1)+(n-1)S(n-1,k)

 

六、 第二类Stirling

1. S(n,k) 表示把 n 个元素划分成 k 个非空集合的方案数,那么假设已经分好了 n-1 个数,之后第 k 个数要么自己独立分成一个集合,要么和其他的集合合并成一个新的集合,因此有 S(n,k)=S(n-1,k-1)+k*S(n-1,k) 。其中 S(n,2)=2^(n-1)-1 ,因为设 {1}{2..n} ,那么 {2..n} 的子集有 2^(n-1) 种,也就是说 1 可以和这个子集合并形成新的集合划分,那么那个减一是如果 {2..n} 全部选上与 {1} 合并,那么就只剩下一个集合了,与题意不符。这类数的变种例如将 n 个不同的球放入 k 个相同的盒子里,且盒子不允许为空。

 

七、整数拆分,就是说整数可以分若干数之和的种类数。设F(n,k) 为将 n 拆分最大数不大于 k 的拆分法,所以要么最大数等于 k ,有 F(n-k,k) 种情况(取走一个 k ,剩下 n-k ),要么最大数小于 k ,有 F(n,k-1) 种情况。边界条件为 F(n,1)=1 F(0,0)=1 F(1,1)=1 F(n,k)=F(n,n)(k>n)

你可能感兴趣的:(挑战编程第六章 组合数学 读书笔记)