poj2411 狀態壓縮dp

2021-06-22 20:54:11 字數 1509 閱讀 4028

一道經典狀態壓縮dp題目。

題意很明確,讓用1*2或2*1的小方格鋪滿地板。根據狀態壓縮的慣用思路,當前行的地板狀態是由當前行和上一行共同決定的,肯定要用乙個二進位制數表示一行的狀態,然後再用狀態轉移方程轉移求解。

這道題可以這麼想,對於每個狀態,如果是1*2的橫著放,將兩個位置都標記為1,如果是2*1的豎著放,那麼將上面位置標記成0,下面位置標記成1,這樣的話,就能保證,如果最後一行鋪滿且沒有2*1的起始方塊,最後一行的狀態肯定全是1,這樣便確定了結果狀態。起始狀態也很明顯,由於第一行上面肯定不存在放磚塊的位置,故除了將第一行全部標記成1的狀態的種數設定成1外,第一行其他狀態全部設為0。然後就是狀態轉移了

狀態轉移有兩種思路:

#include #include #include using namespace std;

int h,w;

int l,now,pre,cnt; //l為當前處理的長度,now表示當前的行狀態,pre表示當前的上一行狀態,cnt記錄狀態數

int status[20000][2]; //0表示上一行狀態,1表示當前行狀態,陣列第一維表示乙個兩行的狀態組

long long int dp[15][20000];

void dfs(int l,int now,int pre)

dfs(l+2,(now<<2)|3,(pre<<2)|3); //當前行橫放乙個1*2的磚塊,那麼上一行要麼是橫放乙個1*2的磚塊,要麼是2*1的下面,總之肯定是1

dfs(l+1,(now<<1)|1,pre<<1); //當前行放2*1的下面部分,那麼上一行肯定是2*1的上面部分,表示為0

dfs(l+1,now<<1,(pre<<1)|1); //當前行放2*1的起始部分,那麼上一行肯定不是2*1的起始部分,也就是說不為0

//這樣得到的任意乙個01字串組,肯定都能用磚塊來鋪滿,不必擔心沒有鋪滿的問題

}int main()

{ while (cin>>h>>w&&h+w)

{l=now=pre=cnt=0;

dfs(l,now,pre);

memset(dp,0,sizeof(dp));

dp[0][(1<

這個**將起始狀態設為全為0,橫鋪兩個為00,豎鋪上為1下為0,這樣合法的末狀態就是全為0的狀態,合法的初狀態較多,需要列舉(讀者可以想想為什麼上一種表示方法初狀態只有乙個,而這個表示方法初狀態卻有多個,跟表示的方法有關)

#include #include #include using namespace std;

int n,m;

long long int dp[15][2500];

bool ok(int s1,int s2)

{ if (s1&s2) //如果兩個狀態有重合的1,則說明都為2*1的上部,狀態衝突

return false;

int s=s1|s2;//否則將兩個狀態合併取或

for (int i=0;i>n>>m&&n+m)

{if (n*m%2==1)

{cout<<0<

poj 2411 狀態壓縮DP

用乙個vector容器來記錄當前狀態下有哪些狀態可以繼承。比如說vec i 裡面的所有的數代表當第一行為i狀態時,第二行的可行狀態。對於狀態i,其二進位制中0的地方表示為當前狀態為豎著的木板的下半部分。其二進位制中1的地方表示為當前狀態為橫著的木板或者豎著的木板的上半部分。include inclu...

POJ 2411 狀態壓縮DP

題目大意 給乙個h w的方格,現給出1 2和2 1的兩種小方塊,求出把h w方格鋪滿的不同方案數 1 h,w 11 分析 首先能想到的是如果h w為奇數,那麼肯定不能放滿,結果為0 如何表示狀態 從題目看資料很小,那麼很容易想到用二進位制來表示狀態,0表示當前方格沒放,1表示放了 這裡用dp r c...

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推出 起...