题目链接:http://acm.uestc.edu.cn/#/problem/show/1690
题意:n*m的矩阵,用1*2的方格去铺满,有多少种方法。
解法:状压DP经典入门题。Hiho上的解法:http://blog.csdn.net/idealism_xxm/article/details/49926109
更加简单的方法
首先我们使决策有序化,因为必须把整个大矩形覆盖,所以每个位置都要覆盖,所以我们可以从上到下,从左到右依次考虑每个位置的放置
考虑状态定义,首先必须有当前要考虑的位置,其次,为了转移,需要有当前行的信息,其次,因为可能竖放影响到下一行,所以需要用状态保存下一行的信息以便状态转移
x,y表示当前需要考虑放小长方形的位置,st1,st2分别是当前行和下一行的情况
dp[x][y][st1][st2]表示当前要考虑(x,y),当前行状态是st1,下一行状态是st2,可以有多少种合法的放置方法
在进行状态转移时,没有检查状态的合法性,可能存在y==m+1的情况,所以这里特判
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
const int maxn = 1005;
int n, m, mask1, mask2;
int dp[maxn][1030];///dp[i][j]表示当前考虑第i行,j的前1~m位表示当前行的状态,后m+1~2*m位表示下一行的状态
int main()
{
while(~scanf("%d%d",&n,&m)){
mask1 = (1<<m)-1;
mask2 = (1<<(m<<1))-1;
memset(dp,0,sizeof(dp));
dp[1][0]=1;
for(int i=1; i<=n; i++){
for(int k=0; k<m; k++){
for(int j=0; j<=mask2; j++){
if((j&(1<<k))==0){
dp[i][j|(1<<k)|(1<<(k+m))]=(dp[i][j|(1<<k)|(1<<(k+m))]+dp[i][j])%mod;
if(k+1<m&&(j&(1<<(k+1)))==0){
dp[i][j|(1<<k)|(1<<(k+1))]=(dp[i][j|(1<<k)|(1<<(k+1))]+dp[i][j])%mod;
}
}
}
}
for(int j=0; j<=mask2; j++){
if((mask1&j)==mask1){
dp[i+1][j>>m]=dp[i][j];
}
}
}
printf("%d\n", dp[n][mask1]);
}
return 0;
}