【牛客 - 301哈爾濱理工大學軟體與微電子學院第八屆程式設計競賽同步賽(高年級)】小樂樂搭積木(狀壓dp)
阿新 • • 發佈:2018-12-06
題幹:
小樂樂想要給自己搭建一個積木城堡。
積木城堡我們假設為n*m的平面矩形。
小樂樂現在手裡有1*2,2*1兩種地磚。
小樂樂想知道自己有多少種組合方案。
輸入描述:
第一行輸入整數n,m。(1<=n,m<=10)
輸出描述:
輸出組合方案數。
示例1
輸入
2 3
輸出
3
說明
示例2
輸入
1 3
輸出
0
示例3
輸入
2 5
輸出
8
解題報告:
這題狀壓dp,,那種很傳統的方法就不貼了,,今天來貼一個更快的方法、、不同點不在於預處理第一行,而是下面的行,也就是直接找到第二行所有符合的狀態,順便找到對應上一行應該有的狀態,直接做和就可以了。
AC程式碼:
/*優化:不去盲目的列舉所有狀態i和j然後判斷狀態j能否到達i,這樣效率很低,因為能到達i的狀態j很少 因此對於每種狀態i,由i區搜尋能到達i的狀態j,大大提高效率 有298ms->32ms */ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <queue> #include <algorithm> #include <map> #include <cmath> #include <iomanip> #define INF 0x3f3f3f3f typedef long long LL; using namespace std; const int MAX=(1<<11)+10; int n,m; LL temp[MAX],dp[MAX],biao[15]; bool check(int i){ while(i){ if(i&1){ i>>=1; if(!(i&1))return false;//第j列是1則第j+1列必須是1 i>>=1;//繼續判斷下一列 }else i>>=1;//繼續判斷下一列 } return true; } void Init(){ memset(temp,0,sizeof temp); for(int i=0;i<biao[m];++i)if(check(i))temp[i]=1;//初始化第一行 } void dfs(int lie,int now,int cur) { if(lie == m) { dp[now] += temp[cur];return ; } if((now>>lie) & 1) { dfs(lie+1,now,cur); if((now>>(lie+1)) & 1) dfs(lie+2,now,cur|(1<<lie)|(1<<(lie+1))); } else dfs(lie+1,now,cur|(1<<lie)); } void DP(){ for(int k=2;k<=n;++k){ for(int i=0;i<biao[m];++i) dp[i]=0; for(int i=0;i<biao[m];++i) dfs(0,i,0); for(int i=0;i<biao[m];++i) temp[i]=dp[i]; } } int main(){ biao[0]=1; for(int i=1;i<12;++i)biao[i]=2*biao[i-1]; scanf("%d%d",&n,&m); //if(n<m)swap(n,m);//始終保持m<n,提高效率 Init(); DP(); printf("%lld\n",temp[biao[m]-1]);//輸出最後一行到達時的狀態必須全部是1 return 0; }