排列组合算法之隔板问题与错排公式

排列组合算法之隔板问题与错排公式

一、获取数组元素的全排列

1.1全排列描述

给定一个数组例如[1,2,3],或['a','b','c'],获取数组元素的所有不同排列方式就叫该数组的全排列。如果数组元素个数为n,那么全排列的个数为n!。

1.2实现代码

可以通过递归方式编写代码实现,也可以使用C++标准模板库STL中的next_permutation函数实现。代码如下:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

string s1, s2;
int n;
char a[10];
int main()
{
    cin>>s1;
    s2=s1;
    n=s1.size();
    sort(s1.begin(), s1.end());
    for(int i=0; i<n; i++) a[i]=s1[i];
    do
    {
        for(int i=0; i<n; i++) cout<<a[i]<<' ';
        cout<<'\n';
    }while(next_permutation(a, a+n));
    return 0;
}

1.3代码说明

上述代码实现了对输入的字符串输出它的全排列的功能,需要注意的是next_permutation函数是根据字典序生成当前序列的下一个排列,因此要使用do while循环形式,如果直接使用while循环会漏掉当前序列本身的一种排列。

二、组合数计算

2.1组合数描述

给定n个不同元素,从中取出m个元素,不计较顺序,求m个元素一共可以有多少种组合,这就是组合数问题,组合的数量记为: C n m C_{n}^{m} Cnm,也可以写为C(n,m),规定 C n 0 C_{n}^{0} Cn0=1, C n m C_{n}^{m} Cnm= C n n − m C_{n}^{n-m} Cnn−m。

C n m C_{n}^{m} Cnm的直接计算公式为 n × ( n − 1 ) × . . . ( n − m + 1 ) ! m ! \frac{n×(n-1)×...(n-m+1)!}{m!} m!n×(n−1)×...(n−m+1)!

递归计算公式为: C n m C_{n}^{m} Cnm= C n − 1 m C_{n-1}^{m} Cn−1m+ C n − 1 m − 1 C_{n-1}^{m-1} Cn−1m−1

将m取值0到n的组合数累加的结果等于2的n次方,公式为:C(n,0)+C(n,1)+C(n,2)+...+C(n,n)=2^n

2.2组合数递归求解代码

求解代码如下:

cpp 复制代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;

int n,m,t;
LL ans[16][16];

LL calc(int x, int y)
{
    if(y==0 || x==y) return ans[x][y]=1;
    ans[x][y]=calc(x-1, y)+calc(x-1, y-1);
    return ans[x][y];
}

int main()
{
    cin>>t;
    for(int i=0; i<=15; i++)
    {
        for(int j=0; j<=i/2; j++)
        {
            if(ans[i][j]==0) calc(i, j);
            ans[i][i-j]=ans[i][j];
        }
    }
    while(t--)
    {
        cin>>n>>m;
        cout<<ans[n][m]<<'\n';
    }
    return 0;
}

三、隔板问题

3.1隔板问题描述

将n个相同的球分为k个有序的组,问有多少种分配方案。

例如第一组4个球,第二组3个球,和第一组3个球,第二组4个球,这是两种不同的组合。

3.2求解思路

根据每组球的数量是否可以为0,分为两种隔板问题。

3.2.1每组球的数量至少为1

这种解法较为简单,n个球共有n-1个空格,从这n-1个空格中选取k-1个插入隔板,则实现了分为k个组,那么分配方案总数为 C n − 1 k − 1 C_{n-1}^{k-1} Cn−1k−1

3.2.2每组球的数量可以为0

此时可以从每个组借一个球一共借出k个球加入n个球中,那么球的总数变为n+k,k个组每组初始状态为-1个球。

问题变为将n+k个球分为k组,每组球的数量至少为1,则分配方案总数为 C n + k − 1 k − 1 C_{n+k -1}^{k-1} Cn+k−1k−1

四、错排公式

4.1错排描述

错位排列的定义是没有任何元素出现在其有序位置的排列。例如对于一个数组a,规定有序位置为a[1]=1,a[2]=2,a[3]=3,那么[2,3,1]就是一个错位排列,而[2,1,3]不是一个错位排列。

4.2错排公式

设数组大小为n,错排数为D(n),则有递推公式为D(n)=(n-1)*[D(n-1)+D(n-2)],n≥3,D(1)=0,D(2)=1。

公式推导:

  1. 对于第一个位置,除了对应的正确元素之外其他元素都可以摆放,因此有n-1种;
  2. 此时考虑第一个位置摆放的元素,它对应的正确位置可以摆放第一个位置对应的正确元素,那么剩下n-2个位置要错排n-2个元素,错排数量为D(n-2);
  3. 第一个位置摆放的元素,如果它对应的正确位置不摆放第一个位置对应的正确元素,那么此时相当于n-1个位置要错排n-1个元素(此处不易理解,读者可以举个具体例子帮助思考),错排数量为D(n-1);
  4. 因此得出D(n)=(n-1)*[D(n-1)+D(n-2)]
相关推荐
wsoz2 小时前
Leetcode链表-day9
c++·算法·leetcode·链表
万法若空2 小时前
ANSI转义码详解
linux·c++
Lumos_7772 小时前
Linux -- 系统调用
linux·运维·算法
一个行走的民2 小时前
深度剖析 Ceph PG 分裂机制:原理、底层、实操、影响、线上避坑(最全完整版)
ceph·算法
WolfGang0073212 小时前
代码随想录算法训练营 Day46 | 图论 part04
算法·图论
南境十里·墨染春水2 小时前
C++笔记 STL——vector
开发语言·c++·笔记
拾-光2 小时前
LTX-Video 2.3 实战:用图片生成视频,消费级显卡也能跑的开源 I2V 模型(GPT Image 2)
java·人工智能·python·深度学习·算法·机器学习·音视频
小O的算法实验室3 小时前
2026年ESWA,考虑曲率约束路径优化的 Dubins-RRT* 运动规划算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
jllllyuz3 小时前
灰狼算法优化的LSSVR程序
算法