状压dp(不知道哪里的题目)
这是一道流传至今的状压dp,好像很多人都不知道他的源头在哪里,但是他作为状压dp的入门却是口口相传,他就是一个经典的贴瓷砖问题
题目:有一个N*M(N<=5,M<=1000)的棋盘,现在有1*2及2*1的小木块无数个,要盖满整个棋盘,有多少种方式?答案对某个数取模。
思路:我们可以看到有一维很小,小到可以状压(滑稽),我们当然是对一维进行状压,一维进行枚举,dfs(i,j,state,nxt)代表第i列,第j行,这一行想填成的状态为state,以及填成state时下一列的状态为nxt
然后我们就可以愉快的转移了(反正大体的思路了就是这样,我也不知道我写的对不对)
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int MOD=1e9+7; int n,m; LL dp[1005][35]; void dfs(int i,int j,int state,int nxt) { if(j==n){ dp[i+1][nxt]+=dp[i][state]; dp[i+1][nxt]%=MOD; return ; } if(((1<<j)&state)==1)dfs(i,j+1,state,nxt); if(((1<<j)&state)==0)dfs(i,j+1,state,nxt|(1<<j)); if(j+1<n&&(((1<<j)&state)==0)&&(((1<<(j+1)&state)==0))) dfs(i,j+2,state,nxt); } int main() { while(~scanf("%d%d",&n,&m)){ memset(dp,0,sizeof(dp)); dp[1][0]=1; for(int i=1;i<=m;i++){ for(int j=0;j<=(1<<n);j++){ dfs(i,0,j,0); } } printf("%lld\n",dp[m+1][0]); } return 0; }