1. 程式人生 > >POJ 2411(狀態壓縮DP)

POJ 2411(狀態壓縮DP)

open long true poj 如果 [0 pri 檢查 out

題意:一個矩陣,只能放1*2的木塊,問將這個矩陣完全覆蓋的不同放法有多少種。

如果是橫著的就定義11,如果豎著的定義為豎著的01,這樣按行dp只需要考慮兩件事兒,當前行&上一行,是不是全為1,不是說明豎著有空(不可能出現豎著的00),另一個要檢查當前行裏有沒有橫放的,但為奇數的1。

狀態表示 dp[state][i]第i行狀態為state時候的方案數

轉移方程 dp[state][i] += dp[state‘][i-1] state‘為i-1行的,不與i行狀態state沖突的狀態

邊界條件 第一行 符合條件的狀態記為1 即dp[state][0] = 1;

#include <algorithm>
#include 
<cstdio> #include <cstring> #define Max 1000001 #define MAXN 11 #define MOD 100000000 #define rin freopen("in.txt","r",stdin) #define rout freopen("1.out","w",stdout) #define Del(a,b) memset(a,b,sizeof(a)) #define INF 0x1f1f1f1f using namespace std; typedef long long LL; const int MAXNUM = (1 << MAXN);
int n, m; int a[MAXN][MAXN]; LL dp[MAXNUM][MAXN]; int kexing[MAXNUM]; inline bool check(int in) { int bit = 0; while (in > 0) { if ((in & 1) == 1) bit++; else { if ((bit & 1) == 1) return false; bit = 0; }
in >>= 1; } if ((bit & 1) == 1) return false; return true; } inline bool check2(int x1, int x2) { if ((x1 | x2) != ((1 << n) - 1)) return false; return kexing[x1 & x2]; } int main() { //rin; for (int s = 0; s < MAXNUM; s++) { if (check(s)) kexing[s] = 1; } while (scanf("%d%d", &m, &n) != EOF) { if (n == 0 && m == 0) break; Del(dp, 0); int full = 1 << n; for (int s = 0; s < full; s++) { if (kexing[s]) dp[s][0] = 1; } for (int i = 1; i < m; i++) { for (int s = 0; s < full; s++) { for (int s1 = 0; s1 < full; s1++) { if (!check2(s1, s)) continue; dp[s][i] += dp[s1][i - 1]; } } } printf("%lld\n", dp[full-1][m-1]); } return 0; }

POJ 2411(狀態壓縮DP)