信件錯排問題分析(動態規劃)

問題描述

有 N 個信件和信箱,每封信件對應一個正確信箱位置。現在它們被打亂,求錯誤裝信方式的數量。保證每一封信都裝在錯誤的位置。

思路

抽象成動態規劃問題

定義一個數組dp[]存儲錯誤方式數量。dp[i]表示,有i封信、i個信箱情況下的錯誤裝信方法總數。

轉移方程建立

對於第N封信而言,假設其裝在了第 K 個信箱中,對於第 K 封信,有兩種情況,(1)信件 K 裝在信箱 N 中;(2)信件 K 未被裝在信箱 N 中。

1. 信件K裝在信箱N中

如下圖所示:
image
我們不看 K 和 N 兩對信件和信箱,只關注剩下 N-2 對信件和信箱,有 dp[N-2] 種錯誤裝信方法。同時, K 的取值範圍: 1~N-1 ,因此共有 (N-1)*dp[N-2] 種錯誤裝信方法。

2. 信件 K 未被裝在信箱 N 中

如下圖所示:
image

先給出結果,該情況的錯誤裝信方法有 (N-1)*dp[N-1] 種。這個 dp[N-1] 是如何得出來,我思考了良久。

我們把問題重新描述一下,思路就會清晰很多。事實上,對於信件 i 來說,信箱 i 是它的“專屬信箱”,每個信件都不能放入自己的專屬信箱,對於n 個信件而言,都需要找其它 n-1 個信箱放入,其錯排方法數爲 dp[n] 。

問題的癥結在於,對於上圖中的信件 K 來說,其專屬信箱,即 K 信箱已經被佔用。

但是,我們可以把信箱 N 當做信件 K 的“專屬信箱”,因爲本情況下,信件 K 也不能放入信箱 N 。所以可以理解成求 N-1 封信件和 N-1 個信箱(除去信件 N)之間的錯排數量問題。所以得到 dp[N-1]。

同理 K 的取值範圍: 1~N-1 ,因此共有 (N-1)*dp[N-1] 種錯誤裝信方法。

綜上,狀態轉移方程
image

代碼

    /**
     * 動態規劃-信件錯排問題
     */
    private int MailMisalignment(int n){
        if(n==0) return 0;
        if(n==1) return 0;
        int[] dp = new int[n];
        dp[0] = 0;
        dp[1] = 1;
        for(int i=2;i<n;++i){
            dp[i] = (i-1)*dp[i-2] + (i-1)*dp[i-1];
        }
        return dp[n-1];
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章