【递推法】错排问题的递推式和推导过程

【递推法】错排问题的递推式和推导过程

  前言:这篇博客是帮助没有见过错排的新人更好的理解错排问题的递推式和推导过程,各位大佬可自行跳过
题目链接:洛谷P1595信封

一、错排问题的定义:

  很多人(包括我之前)对错排的理解都是:
    现在有n个球和n个箱子,第i个球不能放进第i个箱子里,那么有多少种放法
  这样理解当然没错,但是如果出现这样的情况:
    3个球,第1个球不能放入第3个箱子,第2个球不能放入第1个箱子,第3个球不能放入第2个箱子。求放法数
  是错排吗?我们发现其实还是一道错排,虽然第i个球可以放入第i个箱子内,但是每个球都和一个另外箱子建立起了不能放的关系。
  所以我们发现:
  如果每个球都和一个箱子建立起不能放的关系,那么这就是一个错排问题(不管球和箱子的编号是否相同)
  (不过注意,每个球只能和一个箱子建立这种关系,每个箱子也只能和一个球建立这种关系。否则会出现有箱子所有球都可以放的情况

二、前铺的数学知识:

  理解了错排的定义后,做出这道题还要用到一点数学知识:加乘原理(纯小学数学,可以直接跳)
  简要的说一下加法原理和乘法原理(因为实在是太简单):
  加法原理:若一个问题从多种情况中选择,则解法数是每一种情况的方法数之和。 加法原理就类似于"从…或…情况选择一种"
  乘法原理:若一个问题拆分成几步,则解法数是每一步的方法数之乘积。 乘法原理就类似于“先从…步中选择,再从…步中选择"
  虽然这都是一些很简单的东西,但明白本质,推导递推式的时候也会容易理解一些。

三、错排问题的递推式和推导:

  现在我们就开始推导错排问题的递推式。设f(i)是i个球和i个箱子情况下,错排的解法。则当i为1时,f(i)肯定是0;当i为2时,f(i)肯定是1(这是边界条件)
  根据乘法原理,我们把问题拆分成 “先选择第1个球,再选择剩下的n-1个球”,第1个球除了1号箱,其他位置都能放,也就是有(n-1)种选择,那么得到式子:
   (n-1)*剩下n-1个球的放法
  此时,一定有一个球k,它原本不能放的箱子被1号占据(比如说1放入了3,3号球就是这个k)。则剩下n-1个球根据加法原理可以拆分成 "从k号球放入1号箱的情况或不放入1号箱的情况选择一种"
  先看k号球放入1号箱的情况,现在还剩n-2个球没有放,就转化成了n-2个球的错排,即f(i-2);
  再看k号球不放入1号箱的情况。注意,此时k号球和n号箱建立了"不能放"的关系,相当于变成了n-1个球的错排(可以想象成k号球挪到了原来1号的位置称为新的1号,但本质上是因为只要一个球和一个箱子建立起这种关系,不管编号是否相同都属于错排)
  那么n-1个球的放法就是:
  f(n-1)+f(n-2)
  我们把它代入开始的式子,得到:
  f(n) = (n-1)*(f(n-1)+f(n-2))
  这就推出了大家熟悉的那个递推式。最后,本蒟蒻贴上顶部那道题(其实就是个错排)的AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
long long f[25];
int n;
int main(){
	cin >> n;
	f[1] = 0;
	f[2] = 1;
	for(int i = 3;i <= n;i++)f[i] = (i-1)*(f[i-1]+f[i-2]);
	cout << f[n] << endl; 
	
	return 0;
}

萌新第一次发博客,有不当之处欢迎各位大佬指出

猜你喜欢

转载自blog.csdn.net/Sakura_code/article/details/105908559