模板C++ 02数论算法 3排列与组合

2.3排列与组合

1.排列(在乎顺序)

全排列:n个人全部来排队,队长为n。第一个位置可以选n个,第二位置可以选n-1个,以此类推得:P(n,n)=n(n-1)(n-2)……3*2*1=n!(规定0!=1).

部分排列:n个人选m个来排队(m<=n)。第一个位置可以选n个,第二位置可以选n-1个,以此类推,第m个(最后一个)可以选(n-m+1)个,得:

2.组合(不在乎顺序)

n个人m(m<=n)个出来,不排队,不在乎顺序C(n,m)。如果在乎排列那么就是P(n,m),如果不在乎那么就要除掉重复,那么重复了多少?同样选出的来的m个人,他们还要“全排”得到P(n,m),所以得:

组合数的性质1:C(n,k)=C(n-1,k)+C(n-1,k-1

组合数的性质2:n&k==k c(n,k)为奇数,否则为偶数

3.其他排列与组合

1)圆排列:n个人全部来围成一圈为Q(n,n),其中已经排好的一圈,从不同位置断开,又变成不同的队列。所以:Q(n,n)*n=P(n,n)  à>>>  Q(n)=P(n,n)/n=(n-1)

由此可知,部分圆排Q(n,r)P(n,r)/r=n!/(r*(n-r)!)

2)重复排列(有限):k种不一样的球,每种球的个数分别是a1,a2,...ak,

设n=a1+a2+…+ak,这n个球的全排列数,为

n!/(a1!*a2!*...*ak!)

3)重复组合(无限):n种不一样的球,每种球的个数是无限的,从中选k个出来,

不用排列,是组合,为C(n+k-1,k)

证明:假设选出来的数(排好序)1<=b1<=b2<=b3……<=bk<=n

这题的难点就是=号,现在去掉=号,所以有:

1<=b1<b2+1<b3+2<b4+3……<bk+k-1<=n+k-1

中间还是k个数!不过已经不是b系列,而是c系列假设c[i]:=b[i]+i-1,所以1<=c1<c2<c3<c4…….<ck<=n+k-1所以问题就开始转换为无重复组合问题, 即在n+k-1个元素中选中k个的组合数C(n+k-1,k)。

(4)不相邻排列:1~n这n个自然数中选k个,这k个数中任何两个数不相邻数的组合有C(n-k+1,k)证明和(3)相同。

(5)错位排列(简称:错排)

先做一个小问题:5本书,编号分别是1,2,3,4,5,现在要把这5本书是放在编号1,2,3,4,5的书架上,要求书的编号和书架的编号不一样,请问有多少种不一样的放置方法?

例:胸口贴着编号为1,2,....n的n个球员分别住在 编号为1,2,....n的n个房间 里面。现规定每个人住一个房间,自己的编号不能和房间的编号一样。

这就是错排问题。当n=3时,只能为312或231这两种。

题解:递推。刚开始所有球员都住在和自己编号一样的房间里面。然后错排开始了,第n个球员从第出来。

第一种情况:n想和()其中任何一个球员换房间,其他 n-2个人换房间的事情,他们就不管了。其他n-2个球员的的错排数为d[n-2],n可以和前面1~(n-1)对换,所以有(n-1)个d[n-2]。

第二种情况:n想和()其中任何一个球员换房间,但是n只想住在第个房间,而n不想住第个房间。

可能你会这样想:那么可以让住在第号房间里面,然后住在房间。抱歉,生气为什么一开始就去找不直接来找,~~(╯﹏╰) ~~

没办法,把自己胸口的编码换成了,他假装自己是,然后错排1~n-1(也就是 d[n-2])。的时候参与进去,这样自己就不会呆在第号房间了。所以有  (n-1)个d[n-1]。

如果理解了上面两个加蓝色的地方,那么错排的公式就出来了

同时也有

错位排列数列为0,1,2,9,44,265......

(7)Catalan数列

1:有2n个人排成一行进入剧场。入场费5元。其中只有n个人有一张5元钞票,另外n人只有10元钞票, 剧院无其它钞票,问有多少中方法使得只要有10元的人买票,售票处就有5元的钞票找零?

2:一位大城市的律师在她住所以北n个街区和以东n个街区处工作。每天她走2n个街区去上班。如果他从不穿越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路?

3:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?

4:对角线不相交的情况下,将一个凸多边形区域分成三角形区域的方法数?

5:一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?

6:n个结点可够造多少个不同的二叉树?

7:n个不同的数依次进栈,求不同的出栈结果的种数?

其对应的序列为1, 1, 2, 5, 14, 42, 132,....===Catalan数列。

该递推关系的解为

时间: 2024-08-26 01:13:47

模板C++ 02数论算法 3排列与组合的相关文章

模板C++ 02数论算法 1最大公约数 AND 2素数判断

2.1最大公约数Greatest Common Divisor 补充知识:x*y=最小公倍数*最大公约数 int Euclid(int a,int b) { if(b==0) return a; return Euclid(b,a%b); } 2.2素数判断Prime #include<cmath> bool Prime(int n) { int t=sqrt(n); for(int i=2;i<=t;i++) if(n%i==0) return false; return true;

模板C++ 02数论算法 5快速幂及快速乘

2.5快速幂及快速乘 int qmul(int x,int y) { int s=0; while(y) { if(y&1) s=(s+x)%p; x=(x+x)%p; y>>1; } return s%p; } int qpow(int x,int y) { int s=1; while(y) { if(y&1) s=qmul(s,x); x=qmul(x,x); y>>1; } return s%p; }

模板C++ 02数论算法 4矩阵乘法

矩阵乘法:用来求某种 递推关系. 矩阵相乘只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义. 定义 设A为A*M的矩阵,B为M*B的矩阵,那么矩阵C为矩阵A与B的乘积,其中矩阵C中的第i行第j列元素可以表示为: 如下所示: 开一个2*2的矩阵:主要是为了快速幂的方便,一个可以和自己乘上许多次(>=2)的矩阵只有可能是正方形的,所以要开这样一个矩阵. [题目描述] a[1]=a[2]=a[3]=1 a[x]=a[x-3]+a[x-1]  (x>3) 求a数列的第n项对1000000007(

hdu 2586 LCA模板题(离线算法)

http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B&quo

常用数论算法

1.求两数的最大公约数 function gcd(a,b:integer):integer; begin if b=0 then gcd:=a else gcd:=gcd (b,a mod b); end ; 2.求两数的最小公倍数 function lcm(a,b:integer):integer; begin if a<b then swap(a,b); lcm:=a; while lcm mod b>0 do inc(lcm,a); end; 或者利用 最小公倍数=a*b/最大公约数 3

经典算法学习之分治法(以排列、组合程序为例)

分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治法在每层递归是遵循的三个步骤: (1)分解原问题为若干个子问题,这些子问题是原问题的规模较小的实例. (2)解决这些子问题,队规的求解各个子问题,当子问题规模足够小的时候,直接求解. (3)合并这些子问题的解构成原问题的解. 显然归并排序是一个非常经典规矩的分治法的例子,鉴于之前已经写过一篇关于归并排序的博文,这里不在使用归并排序作为例子. 注意分治法的每一层递归

【C/C++学院】0825-类模板/final_override/类模板与普通类的派生类模板虚函数抽象模板类/类模板友元/位运算算法以及类声明/Rtti 实时类型检测/高级new创建/类以及函数包装器

类模板 类模板多个类型默认类型简单数组模板 #pragma once template <class T=int>//类模板可以有一个默认的值 class myArray { public: myArray(); ~myArray(); }; #include "myArray.h" template <class T=int>//每一个函数都需要加上一个默认的值 myArray<T>::myArray() //类模板成员函数在外部,需要加载类型初始

利用标准库算法求解排列组合

以前求序列的排列时,最常用的方法就是递归回溯,现在发现其实像这样有特定算法的重复性工作是可以在STL标准库中找到答案的. 在STL的变序性算法中,有两个用于排列元素的算法分别如下: bool next_permutation(Iterator beg,Iterator end) bool prev_permutation(Iterator beg,Iterator end) 这两个算法的功能也很简单,next_permutation()会改变区间(beg,end)内的元素次序,使它们符合"下一个

java中关于排列和组合的有关算法

收集的排列加组合的各种算法,还有待完善: 一.利用二进制状态法求排列组合,此种方法比较容易懂,但是运行效率不高,小数据排列组合可以使用 import java.util.Arrays; //利用二进制算法进行全排列 //count1:170187 //count2:291656 public class test { public static void main(String[] args) { long start=System.currentTimeMillis(); count2();