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

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

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

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,规定有序位置为a1=1,a2=2,a3=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)
相关推荐
oyguyteggytrrwwwrt14 小时前
自制交叉线路识别算法
算法
手写码匠14 小时前
华为云Flexus+DeepSeek征文|Dify 多智能体协同编排实战:R1 规划 + V3 执行,构建企业 Agent 团队
人工智能·深度学习·算法·aigc
晓天衡宇•评测社区15 小时前
FSR-Bench 前沿科学推理榜单发布:GPT-5.5 居首,“会推理”未必“能答对”
算法
程序喵大人16 小时前
【C++进阶】STL算法与函数对象 - 02 sort为什么需要随机访问迭代器
开发语言·c++·算法
hanlin0316 小时前
动态规划专练:力扣第121、122题
笔记·算法·leetcode
To_OC16 小时前
LC 74 搜索二维矩阵:换皮的二分查找,我居然一开始没看出来
javascript·算法·leetcode
文心快码BaiduComate16 小时前
文心快码荣获“中国优秀软件产品”,实力再获国家级认可
算法·代码规范
玖玥拾16 小时前
LeetCode 189 轮转数组
算法·leetcode
ZhangShao060717 小时前
题解:CF2249B
c++·算法
小玮看世界17 小时前
[Python]线段树与二分法
数据结构·算法