題目大意:給乙個h*w的方格,現給出1*2和2*1的兩種小方塊,求出把h*w方格鋪滿的不同方案數(1<=h,w<=11)
分析:首先能想到的是如果h*w為奇數,那麼肯定不能放滿,結果為0
如何表示狀態:從題目看資料很小,那麼很容易想到用二進位制來表示狀態,0表示當前方格沒放,1表示放了
這裡用dp[ r ][ cur ]表示前 r-1 行放滿,第 r 行狀態為 cur 時的方案數,同理,dp[ r-1 ][ lst ]表示前 r-2 行放滿,
第 r-1 行狀態為 lst 時的方案數; 狀態 lst 是由 cur 狀態推出來的( [1] 為什麼?),
所以dp[ r ][ cur ] = dp[ r ][ cur ] +dp[ r-1 ][ lst ]; 那麼dp[ h ][ (1<
[1] 先表示一下狀態,我們在考慮第 r 行,只考慮前 r 行,一共有 3 種狀態(cur表示第 r 行,lst表示第 r-1 行):
1、豎直放 cur<<1 | 1 , lst<<1
2、橫著放 cur<<2 | 3, lst<<2 | 3
3、不放 cur<<1, lst<<1 | 1
先解釋一下:假設 cur = lst = 0, 假如豎直放,那麼 cur = 1, lst = 0, 意思是第 r 行第1列放,第 r-1 行第1列
不放(因為第 r 行要堅直放,所以第 r-1 行第 1 列不能放),直到放完最後一列,出現了兩個狀態 cur 和 lst,
其中 lst 不就是由 cur 狀態推出來的麼?並且保證第 r-1 行是滿的!
其中第一行只有兩種狀態,因為第一行上邊沒有,所以不能豎直放……
舉個例子:h = 3, w = 2; dp[ r ][ cur ] += dp[ r-1 ][ lst ];
仔細看一看應該就可以看的懂了!下面是**:
#include#include#include#include#include#include#include#includeusing namespace std;
int h, w;
long long dp[12][2100];
void dfs(int r, int c, int cur, int lst)
if(c + 1 <= w) dfs(r, c+1, cur<<1, lst);
if(c + 2 <= w) dfs(r, c+2, cur<<2|3, lst);
}else
if(c + 1 <= w)
if(c + 2 <= w)
}}int main()
if(h < w) swap(h, w);
memset(dp, 0, sizeof(dp));
for(int r = 1; r <= h; ++r)
dfs(r, 0, 0, 0);
printf("%lld\n", dp[h][(1<
如有錯誤歡迎指正。 poj 2411 狀態壓縮DP
用乙個vector容器來記錄當前狀態下有哪些狀態可以繼承。比如說vec i 裡面的所有的數代表當第一行為i狀態時,第二行的可行狀態。對於狀態i,其二進位制中0的地方表示為當前狀態為豎著的木板的下半部分。其二進位制中1的地方表示為當前狀態為橫著的木板或者豎著的木板的上半部分。include inclu...
poj2411 狀態壓縮dp
一道經典狀態壓縮dp題目。題意很明確,讓用1 2或2 1的小方格鋪滿地板。根據狀態壓縮的慣用思路,當前行的地板狀態是由當前行和上一行共同決定的,肯定要用乙個二進位制數表示一行的狀態,然後再用狀態轉移方程轉移求解。這道題可以這麼想,對於每個狀態,如果是1 2的橫著放,將兩個位置都標記為1,如果是2 1...
poj 2411 狀態壓縮dp
題意 乙個n m的矩形用 1 2 的卡牌填滿 問共有多少種方法 方法 狀態壓縮 動規的思想 dp i j 表示前i 1行全部填滿 第i行狀態為j的方法總和 狀態j的二進位制狀態 0 表示該位被占用了 1 代表 該為是空的 狀態轉移方程 dp i j sum dp i 1 k 狀態j可由狀態k推出 起...