我是一名鋪磚匠 鋪磚問題彙總(DP)

2021-09-23 10:47:52 字數 3688 閱讀 3351

鑑於多次遇到鋪磚問題,因此目前遇到對此類問題進行總結:

鋪磚問題主要分類:

1.簡單的一維鋪磚問題

2.二維鋪磚問題

2*1的磚是否可以鋪滿n*m的地面

3.二維鋪磚鋪滿有多少種方法

a.2*1的磚鋪滿2*m的地面有多少種方法?

b. 2*1的磚鋪滿n*m的地面有多少種方法?

【問題描述】

有一長度為n(1<=n<=10)的地板,給定兩種不同瓷磚:一種長度為1,另一種長度為2,數目不限。要將這個長度為n的地板鋪滿,一共有多少種不同的鋪法?(藍橋杯演算法訓練試題)

【解題思路】

一道簡單的遞推或者說是dp的題目

n = 1時,只有一種方法 一塊長為1的磚

n = 2時,兩種方法 兩塊長為1的磚,

一塊長為2的磚

n = 3時,三種方法  三塊長為1的磚

,先一塊長為1的磚,後一塊長為2的磚,

先一塊長為2的磚,後一塊長為1的磚。

以n=3舉例,我們可以這樣看

a.先鋪好了一塊1格的地面,那麼再鋪一塊長為2的磚就可以達到3格

b.先鋪好了一塊2格的地面,那麼再鋪一塊長為1的磚就可以達到3格

即第i格地面的鋪設方式為  第i-1和第i-2的方式的和。

從上面我們可以逐漸發現遞推公式  或  狀態轉移方程  :dp[i] = dp[i-1]+d。p[i-2];

【**】

#include using namespace std;

int dp[50];

int main()

cout << dp[n];

return 0;

}

【問題描述】

某年夏天,位於希格瑪大廈四層微軟亞洲研究院對辦公樓的天井進行了一次大 規模的裝修.原來的地板鋪有 n×m 塊正方形瓷磚,這些瓷磚都已經破損老化了,需要予以 更新.裝修工人們在前往商店選購新的瓷磚時,發現商店目前只**長方形的瓷磚,現在的 一塊長方形瓷磚相當於原來的兩塊正方形瓷磚, 工人們拿不定主意該買多少了, 讀者朋友們 請幫忙分析一下:能否用 1×2 的瓷磚去覆蓋 n×m 的地板呢?

【解題思路】

考慮n,m的奇偶性

a.n*m為奇數,n和m都是奇數,1*2的瓷磚必定不可覆蓋

b.n和m至少有乙個是偶數,可以設m為偶數(若n為偶數可以交換n和m,保證m為偶),可以知道用1*2的磚鋪1*m的磚必定可以鋪滿,需要m/2塊磚。這樣n*m就可以轉化為重複鋪n次1*m的地面的情況

【**】

#include using namespace std;

int main()

else

cout << dp[m];

return 0;

}

ⅱ.2*1的磚鋪滿n*m的地面,有多少種方式(狀態壓縮+dp)poj 2411:mondriaan's dream

【題意簡述】

有1*2的磚,問鋪滿n*m的地面需要多少種方式

【解題思路】

解題之前要明確的一些定義或者表示:

1. 考慮n*m的情況:

a.n*m為奇數時,無法鋪設

b.n*m為偶數時,可以轉化為上邊的2*m的問題,可以看作是k*2*m(n = 2*k).故其實仔細分析兩行就可以分析出整個地面的鋪法。

2.對於所鋪磚的表示:

來自(這樣表示是為了方便使用狀態壓縮(狀態壓縮自行學習),將鋪磚的狀態用0和1來表示。該矩陣的磚塊擺放方法和該矩陣的二進位制表示法是一一對應的。

3. 對於兩行的是「匹配」的定義:

設當前行所儲存的數是cur_,上一行儲存的數為pre_,如果cur_和pre_對應的二進位制數可以表示把兩行的地面鋪滿,則說其是匹配的。

舉個栗子:

對於乙個2*5的地面 0 11 11 (十進位制15)和  1 11 11 (十進位制31)就是合法的,而15和15就是非法的。

磚塊擺放有如下的關係:

如果當前位置(i,j)橫著放,狀態為11,那麼上一行(i-1,j)也必須是11,之後我們要考慮(i,j+2)

如果當前位置(i,j)豎著放,狀態為1,上一行(i-1,j)為0,之後我們要考慮(i,j+1)

如果當前位置(i,j)不放,那麼上一行此位置(i-1,j)為1,當前位置為0,之後我們要考慮(i,j+1)

4.對於dp狀態的定義:

dp[i][num]:在第i層為num時(在上述例子中 15和30 就是num)的方式數。

整體思路:

1.每行有三種選擇,橫著放,豎著放, 不放,如果用1表示橫著放和豎著放的第二個,0表示豎著放的第乙個和不放,每次都是兩行之間的轉換, 找出可以互相轉換的狀態就可以,採用深搜,找到所有pre_和cur_是匹配的二進位制狀態,將其存到pre[cnt],cur[cnt]這兩個陣列中。就拿上面例子來講,可以寫pre[0] = 15,cur[0] = 31;

2.第0行可以看作是全部鋪成1(看作不需要在**中寫出),那麼第0行看作有1種鋪磚方法,即dp[0][(1

3.在迴圈中依次遍歷在pre[cnt]和cur[cnt]儲存下來的可以「匹配」二進位制狀態,狀態轉移方程:dp[i][cur[j]] += dp[i - 1][pre[j]];

最後要求的結果就是dp[n][(1

#include #include #include using namespace std;

const int max = 5e6;

long long dp[15][1 << 12];

int pre[max], cur[max];

int cnt, n, m;

void solve(int l, int pre_, int cur_)

solve(l + 2, (pre_ << 2) | 3, (cur_ << 2) | 3);

//橫著放置

//每次 pre_和cur_ 按位或3 是為了將(i,j)和(i,j+1)置1,表示橫鋪磚,鋪完以後考慮(i,j+2)

solve(l + 1, (pre_ << 1), (cur_ << 1) | 1);

//豎著放置

//每次 cur_ 按位或1 是為了將(i,j)置1,表示豎鋪磚,鋪完以後考慮(i,j+1)

solve(l + 1, (pre_ << 1) | 1, (cur_ << 1)); //不放置方塊

}int main()

printf("%lld\n", dp[n][(1 << m) - 1]);

//cout << dp[n][(1 << m) - 1]<

}return 0;}/*

1 21 3

1 42 2

2 32 4

2 11

4 11

0 0*/

/*ans10

1235

14451205

*/

我是一名黑客我也是一名程式設計師

黑客 大陸和香港 黑客 台灣 駭客,英文 hacker 通常是指對電腦科學 程式設計和設計方面具高度理解的人。在許多黑客型別電影被大家所熟知後,一些程式設計崇拜者便將成為一名黑客當成了自己的奮鬥目標。著名程式設計師,同時也是最早的計算機社群名人之一的 eric raymond 是這樣定義黑客的,聰明...

我是一名it程式設計師

我是一名it程式設計師 hello,這是我的第一篇部落格,一直以來的學習中,都是從很多優秀的人發的微博中,收穫了不少,感謝這些作者的付出。所以,我想借助這個平台來記錄一些自己的東西,通過自己的鑽研來轉化成具體的東西,有些態度需要表達,有些知識需要外顯,有很多東西都需要去磨練,寫部落格就是這麼乙個磨練...

如果我是一名測試經理

如果我是一名測試經理,在每乙個專案開始時,我要做以下幾件事情 1.知道軟體的使用者群體 這決定我們在測試中所扮演的角色,即以什麼樣的使用者眼光去看待這個軟體 2.了解開發部內部各模組的任務分配情況,便於之後在測試中遇到問題時與對應模組的負責人進行溝通 3.明確本次開發的開發流程 開發周期和開發成本,...