题目链接: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;
}