從hihoCoder的一道題學習狀態壓縮 dp

2022-01-12 06:15:25 字數 2423 閱讀 7085

有1個n*m的盤子,要裝2*1的蛋糕,問有多少種方法?(結果對1000000007取餘,其中2≤n≤1000,3≤m≤5)

最簡單的例子如下:

下面我們來分析:

這個題目類屬於狀態壓縮dp,對於狀態壓縮dp,其實最簡單的理解就是把狀態用位元位的形式表示出來,我們會在下面用例子來說明。

假如現在我們在鋪磚 位置(i,j), 並且假設之前的位置已經鋪設好的了,在這個位置,我們的選擇:

1. 不用鋪磚了,可能在(i-1, j)的時刻已經被豎著鋪上了,然後考慮的是(i, j+1)

2. 橫鋪磚,將(i, j+1)也鋪上了,然後考慮的是(i, j+2)。

3. 豎著鋪磚,(將i,j)和(i+1,j)鋪上乙個豎立的轉頭。

所以我們如下翻譯我們的選擇,在位置(i, j) 如果我們選擇橫著貼磚,那麼將(i, j), (i, j+1)都填寫成1,如果豎著貼磚,我們將(i,j)填寫成0,將(i+1, j)填寫成1.

問題1:為什麼要這麼計數呢,我覺得應該這樣理解:

1. 在橫著貼磚的時候,(i, j), (i, j+1) 都是1,這個值其實對下一行如何選擇沒有影響。

2. 豎著貼磚的第二個,我們也選擇了1, 因為這個磚頭結束了,對下一行如何選擇依然沒有影響。

3. 而豎著的第乙個磚頭,這個磚頭是對下面有影響的,如果(i,j)是0,那麼(i+1,j)只有是1的情況下才能滿足條件。

即當設為1表示對下一行沒有任何影響了。

問題2:如何判斷當前狀態與上一行的狀態是否相容

其實我們在上面已經基本給出分析, 如果我們現在鋪設 (i,x) x這裡表示第i行,第x列

1. 如果值 i  行,j 在x位上的值是0, 那麼第 i-1行,j的值在x位上一定是1。因為不可能在同一列相鄰的位置鋪兩個豎著的 第乙個,如果滿足下一步測試的是(i, x+1), 否則直接返回不相容。

2. 如果值 i  行,j在x位置的值是1 .

那麼有可能有兩種情況:

1. (i-1, x)是0, 這個時候一定是豎著鋪設了,下一步檢測的是(i, x + 1)

2. (i-1, x) 是1, 如果是這樣的話,那麼(i,

x)一定是要選擇橫著鋪了,那麼(i,x+1)也一定是1,並且(i-1,x +

1)一定是1(如果是0,就是豎著鋪了),如果不滿足就返回不相容,滿足條件 就測試(i,x + 2)

對於第一行的相容性,我們要做一下特別的分析,在第一行中,要麼放0, 要麼放1。

加入當前測試的是 dp(0, j)的第 x的位元位,即第0行,x列

1. 如果x是1,那麼 x + 1 也一定是1,然後測試到 x + 2

2. 如果x是0, 那麼直接測試下乙個 x + 1

特別注意:這裡的判斷的(i,x)一定不是由(i,x-1)位橫著鋪磚過來的,否則直接x=x+2,就不會來判斷(i,x)位了。

問題3:為什麼可以使用動態規劃演算法來解決這個問題?

這就得從動態規劃的特性上去找:

(1)最優子結構

用f[i][j]表示第i行j狀態鋪磚塊的方案數,一定等於i-1行所有的能與狀態j相容的狀態k的方案的總和。

(2)重複子問題

求f[i][j]即第i行的每乙個狀態一定要用到第i-1行的各個狀態。

問題4:從狀態壓縮的特點來看,這個演算法適用的題目符合以下的條件:

1.解法需要儲存一定的狀態資料(表示一種狀態的乙個資料值)

,每個狀態資料通常情況下是可以通過二進位制來表示的。這就要求狀態資料的每個單元只有兩種狀態,比如說棋盤上的格仔,放棋子或者不放,或者是硬幣的正反兩面。這樣用 0 或者 1 來表示狀態資料的每個單元,而整個狀態資料就是乙個一串 0 和 1 組成的二進位制數。

2.解法需要將狀態資料實現為乙個基本資料型別,比如int,long等等,即所謂的狀態壓縮。狀態壓縮的目的一方面是縮小了資料儲存的空間,另一方面是在狀態對比和狀態整體處理時能夠提高效率。這樣就要求狀態資料中的單元個數不能太大,比如用

int 來表示乙個狀態的時候,狀態的單元個數不能超過 32(32 位的機器)。

//注:j&(1

#define swap(a,b) a=b-a+(b=a)

#define false 0

#define true 1

int testfirstline(int j,int m){

int i=0;

while(i

參照:

一道演算法題

兩個燒杯,乙個放糖乙個放鹽,用勺子舀一勺糖到鹽,攪拌均勻,然後舀一勺混合 物會放糖的燒杯,問你兩個燒杯哪個雜質多?一樣多吧 對的 為啥?是不是因為 糖和鹽本來就是均勻的 因為,就算不攪拌均,你放一勺過去,那邊放一勺不含雜質的過來,那麼都是一勺雜之 如果攪拌均勻的話也是一樣 小依 21 45 32 也...

一道演算法題

1.上午主要做了對翻譯任務的劃分,下午把 翻譯完畢。2.明天要講的演算法題 對乙個集合,求出其連續元素組成的子集中,和最大的子集 我對這道題的理解是 1 若集合中最小值大於0,意味著所有的都大於0,則最大的子集和,為所有值加起來 2 若集合中最大值小於0,意味著所有的都小於0,則最大的子集和,為集合...

一道演算法題

include using namespace std const int size 5 int max sub array const int a,int n,int m int max matrix const int a size int row,int col,int subsize int...