这篇随笔讲解信息学奥林匹克竞赛比较常见的一种题型——排列组合问题。阅读并理解本篇随笔要求读者具备不低于高中一年级的数学素养,而且了解信息学中递归、深搜算法的基本实现方式,能理解通常的递归程序。php
从\(n\)个不一样元素中,选出\(m\)个元素按照必定顺序排成一列,叫作从\(n\)个不一样元素中取出\(m\)个元素的一个排列。c++
从\(n\)个元素中选出\(m\)个元素的全部排列的个数,叫作从\(n\)个不一样元素中取出\(m\)个元素的排列数。算法
当\(n=m\)时全部的排列状况叫作全排列。数组
从\(n\)个不一样元素中,选出\(m\)个元素并成一组,叫作从\(n\)个不一样元素中取出\(m\)个元素的一个组合。spa
从\(n\)个元素中选出\(m\)个元素的全部组合的个数,叫作从\(n\)个不一样元素中取出\(m\)个元素的组合数。3d
通俗地说,组合不分顺序,而排列分顺序,也就是说,对于数列\(1,2\),有如下两种排列:\(1,2\)和\(2,1\),可是仅有一种组合\(1,2\)或\(2,1\).code
从\(n\)个不一样元素中,选出\(m\)个元素的排列数,数学表示为:\(A_n^m\).blog
计算公式以下:
\[ A_n^m=n(n-1)(n-2)\cdots(n-m+1)=\frac{n!}{(n-m)!} \]递归
从\(n\)个不一样元素中,选出\(m\)个元素的组合数,数学表示为:\(C_n^m\).get
计算公式以下:
\[ C_n^m=\frac{A_n^m}{m!}=\frac{n!}{m!(n-m)!} \]
某个数列的全排列数\(f(n)\),计算公式以下:
\[ f(n)=n! \]
例题:生成全排列(深搜基础题)
给定\(n\),生成\(1-n\)的全排列。
咱们考虑用递归来解决全排列问题:
递归出口是当x==n+1地时候,绝对不能仅仅等于n!!
咱们的递归部分使用标记数组和数列数组实现,具体实现方法能够参照下图:
咱们递归的过程大致是如下的思路:
三个数位可能出现1-3每一个数,因此咱们使用递归算法求解的时候,先圈定这一个值,而后继续下搜,遍历完这“一条链”的时候,就上回一个数位看看还有没有其余选择,这样就保证了解不重不漏。
例题代码:
#include<bits/stdc++.h> using namespace std; int n,a[20],v[20]; void dfs(int x) { if(x==n+1) { for(int i=1;i<n;i++) printf("%d ",a[i]); printf("%d\n",a[n]); return; } for(int i=1;i<=n;i++) { if(v[i]==0) { a[x]=i; v[i]=1; dfs(x+1); v[i]=0; } } } int main() { scanf("%d",&n); dfs(1); return 0; }