【遞推法】錯排問題的遞推式和推導過程

【遞推法】錯排問題的遞推式和推導過程

  前言:這篇博客是幫助沒有見過錯排的新人更好的理解錯排問題的遞推式和推導過程,各位大佬可自行跳過
題目鏈接:洛谷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;
}

萌新第一次發博客,有不當之處歡迎各位大佬指出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章