哈爾濱理工大學軟體與微電子學院第八屆程式設計競賽同步賽(高年級)B 小樂樂搭積木 (狀態壓縮)
阿新 • • 發佈:2018-12-04
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K64bit IO Format: %lld
題目描述
小樂樂想要給自己搭建一個積木城堡。 積木城堡我們假設為n*m的平面矩形。 小樂樂現在手裡有1*2,2*1兩種地磚。 小樂樂想知道自己有多少種組合方案。輸入描述:
第一行輸入整數n,m。(1<=n,m<=10)
輸出描述:
輸出組合方案數。示例1
輸入
2 3
輸出
複製3
說明
示例2輸入
1 3
輸出
複製0示例3
輸入
2 5
輸出
8
題目大意:
給你一塊n*m的方塊,以及若干1*2的小木板,問你有多少種方式能夠使小木板填滿方塊。
狀壓DP模板題。和POJ2411雷同。
摘自focus_best的csdn部落格:
首先我們定義如下這種填充表示方式:如果一個骨牌是橫著放的,那麼它所在的兩個方格都填充1.如果它是豎著放的,那麼它所在的兩個格子中,上面的那個填0,下面的這個填1.由此可以得到斷言:該矩陣的骨牌擺放方法和該矩陣的二進位制表示法是一一對應的。
現在我們專注於這個問題:如何求相鄰兩行二進位制值的對應關係?可以列舉i-1行的所有二進位制值情況,然後判斷這個值本身是否合法,如果合法(其實只要這行是中間行所有二進位制值都合法的,因為首行我們虛構了第0行為全1序列,最後一行我們只需要全1序列對應的值),再通過它推斷出和它相容的第i行二進位制值(和i-1行二進位制值相容的第i行二進位制為:第i-1行為0的位,第i行應為1。第i-1行為1的位,第i行為0或1,且如果第i行為1那麼表示第i行此時的對應位置是橫著放的,應該有偶數個連續的1才合法,只需判斷i-1行中為1的位在第i行中如果也為1必須偶數個這樣的1相連)。
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <queue> #include <deque> #include <stack> #include <map> #include <set> typedef long long ll; const int mod=1000000007; const int inf=1000000000; const int maxn=10; const int maxm=200; int n,m; int dp[maxn+5][2<<(maxn+5)]; int main() { scanf("%d%d",&n,&m); memset(dp,0,sizeof(dp)); dp[0][(2<<(m-1))-1]=1; for(int i=1; i<=n; i++) { for(int k=0; k<=((2<<(m-1))-1); k++)//i行 { if(i==n&&k<((2<<(m-1))-1)) continue; for(int j=0; j<=((2<<(m-1))-1); j++)//i-1行 { bool flag=true; for(int p=0,cnt=0; p<=m-1; p++) { if((j&(1<<p))==0) { if(cnt%2) flag=false; else cnt=0; if((k&(1<<p))==0) flag=false; } if((j&(1<<p))>0) { if((k&(1<<p))>0) cnt++; else { if(cnt%2) flag=false; else cnt=0; } } if(p==m-1) { if(cnt%2) flag=false; } if(!flag) break; } if(flag) { dp[i][k]+=dp[i-1][j]; } } } } printf("%d\n",dp[n][((2<<(m-1))-1)]); return 0; }View Code