基础理论:
- 排列
有限集的子集按某种条件的序化法排成列、排成一圈、不许重复或许重复等。
从n个不同元素中每次取出m(1≤m≤n)个不同元素,排成一列,称为从n个元素中取出m个元素的无重复排列或直线排列,简称排列
五个字母全排列有5!=120
- 组合
从n个不同元素中每次取出m个不同元素(0≤m≤n),不管其顺序合成一组,称为从n个元素中不重复地选取m个元素的一个组合。
所有这样的组合的总数称为组合数,这个组合数的计算公式为:
1、对于相同元素的有序分组问题(利用隔板法)
参考博客:http://www.sohu.com/a/230556468_301997
【例1】现有7个完全相同的小球,将它们全部放入编号为1,2,3,4的四个盒子中,每个盒子至少放一个球,问有多少种不同的放法?
【思路点拨】这道题满足隔板法基本模型的三大条件(1.有若干个相同的元素;2. 将元素有序分组,每组至少有一个元素;2. 元素不能有剩余),所以我们可以直接应用隔板法。首先我们将7个小球排成一排。在7个小球中间一共有6个间隔,在这6个间隔中我们挑出3个间隔插入隔板,这样我们就将小球分成了四份,并且每一份都至少有一个小球。接着我们将这四份小球按从左到右的顺序依次放入1-4号四个盒子中,就得到了对应的一种放法。这样一来,每一种隔板的插法就对应了一种小球的方法。6个间隔中插入3个隔板的插法共20种,即本题共有20种不同的放法。
【方法总结】将个相同的元素有序的放入个盒子中(不允许空盒),相当于在个间隔中插入个隔板,因此不同的放法与不同的隔板插法种数相同,共有种放法。这里的是组合数种的基本公式,其计算公式为【 组合C(n,m)=P(n,m)/P(m,m) =n!/m!(n-m)!】。
n=6,m=3
2、变式(1):受限制分组问题
【例2】现有12个完全相同的小球,将它们全部放入编号为1,2,3,4的四个盒子中,每个盒子至少放两个球,问有多少种不同的放法?
【思路点拨】每个盒子我只要至少放一个球就可以啦。也就是说只要让每个盒子里提前都装入一个球,那就可以用隔板法。
所以先拿出4个球,分别装入四个盒中,现在每个盒子里都有1个球了!这样一来问题就变成了将剩下8个相同的球,有序地装入四个盒子中,每个盒子中至少放入1个球,有多少种放法?这还不简单,直接应用刚才基本隔板法模型的结论,在7个间隔中插入3个隔板。
【方法总结】本题为隔板法的变式,原理在于需要先在每个盒子中放入一定数量的小球,再转化为隔板法的基本模型。总结如下:将个相同的元素有序的放入个盒子中(每个盒子中至少放入个元素,),需要先在每个盒子中放入个元素,再将剩余元素利用隔板法放入个盒子中
n=7 m=3
【例3】现有12个相同的小球,将它们全部放入编号为1,2,3,4的四个盒子中,要求每个盒子中的小球个数不小于其编号数,问不同的放法有多少种?
【思路点拨】这道题和例2有些类似,必须要先在某些盒子中放入某个数量的小球,才能转化为隔板法解决。比如2号盒子中最终至少要有2个小球,所以考试君在2号盒子中先放入1个球。同理在3号盒子中先放入2个球,4号盒子中先放入3个球。这样保证每个盒子中只需要再至少放入1个球就可以达到要求。故对剩余6个球用隔板法放入四个盒子中.
【方法总结】本题同样为隔板法的变式,总结如下:当每个盒子均不是空盒且元素数量要求不同时,我们需要先放入一定数量的元素,使得每个盒子中只需要再至少放入1个元素就可以达到要求。再对剩余的元素利用隔板法放入盒子中。
n=5,m=3;
【例4】现有8个完全相同的小球,将它们全部放入编号为1,2,3的三个盒子中,允许出现空盒,问有多少种不同的放法?
【思路点拨】我们先借3个球(有多少个盒子借多少个),让我用隔板法分个球”。成功地借到了3个球之后,这时候我们就可以这样来操作。加上原来地8个球,现在共有11个球,利用隔板法将它们放到三个盒子中,共有种放法。对于每一种放法,考试君都从每个盒子中拿出一个球还回去。当盒中分到一个球之后还回1个球,该盒实际上是空盒;分到两个球后还回1个球,该盒实际上只含一个球,依此类推。这样就成功地将8个相同的小球分入了三个盒中,允许有空盒的共有45种放法。
【方法总结】将个相同的元素有序的放入个盒子中(允许空盒),需要先通过外部力量另外借到个相同的元素,转化为将个元素用隔板法放入个盒子中(最后每个盒子都拿出一个球还回去),所以共有种放法。
n=10,m=3
编程例题
将20个球放进12个不同的袋子,每个袋子可以放0-20个球,有多少种放法?分析如何计算,然后编程解答。
进阶问题:每个袋子只能放0个、2个或3个球,该如何计算?
链接:https://www.nowcoder.com/questionTerminal/b01b4a95413040eaa1effbd34280c78c
来源:牛客网
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 写入球的个数
int ball;
// 写入袋子的个数
int pack;
Scanner scan = new Scanner(System.in);
System.out.println("请输入球的个数");
ball = Integer.parseInt(scan.next());
System.out.println("袋子个数");
pack = Integer.parseInt(scan.next());
System.out.println(getban(ball, pack));
}
// 隔板法
public static long getban(int ball,int pack)
{
// 由于无法保证每个袋子都能装上一个球,无法使用隔板法,
// 所以故意往每个袋子加1个球,当排序的时候可以往每个袋子里减一个球就可以了
long result = 1;
int newball = ball + pack;
// 所以每个球的空隙有newball -1个
int newballair = newball -1;
// 因为需要放入12-1个袋子(插入12-1块板),所以用公式C(newballair,pack-1)
/*
* C(m,n) = m!/n!*(m-n)!
*/
for(int i = newballair - (pack - 1) + 1; i <= newballair ; i++)
{
result *= i;
}
return result / factorial(pack-1);
}
// 阶乘方法
public static long factorial(int num)
{
if(num == 1)
{
return 1;
}
else
{
return num * factorial(num-1);
}
}
}
例题2:五个球从盒子里拿出来,打乱顺序放回去,均不在原位的排列数是多少()
思路:首先我们可以把五个球看成abcde,然后分为以下五种情况来排列
- 首先,a放在任意位置(想象成a右移),则有四种不同的排列
- a占b的位置,则cde有两种排列方式,分别是ecd和dec(e的两次右移)
- a不占b的位置(a,b不交换位置),B的位置没有被A占:则B的位置有3种选择,C的位置有3种选择(因为A在这3个里面,A无论在CDE的哪个位置上,都没有问题,只要A的位置定了,另外两个的位置肯定也定了,因为它们只能交换位置),所以是 3*3种
概率题
https://www.asklib.com/view/12798def.html
例子:
1000个钱币中有10个金币,取一次钱币是金币的概率为0.1,取两次呢,取n次呢
思路:求得每次取不到的概率,用1减去这个概率即可。
dp[n]=990-(n-1)/1000-(n-1) *dp[n-1],dp[0]=1
最终结果1-dp[n]