已经没办法再简单的状压dp入门练习

题目:
有一个N*M(N<=5,M<=1000)的棋盘,现在有1*2及2*1的小木块无数个,要盖满整个棋盘,有多少种方式?答案只需要mod1,000,000,007即可。

例如:对于一个2*2的棋盘,有两种方法,一种是使用2个1*2的,一种是使用2个2*1的。
分析:此题由于N比较小,所以可以通过状态压缩,去搜索每一个状态,然后根据前一列对后一列的影响,这样我们只要求出第m+1列状态为0的情况的个数,就是正解

accode:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int maxn = 100;
const int mod = 1e9 + 7;
int T, n, m;
ll dp[1005][(1 << 5) + 5];
void dfs(int i, int j, int state, int nex) {
    if (j == n) {
        dp[i + 1][nex] += dp[i][state];
        //cout << i + 1 << " " << nex << " " << dp[i + 1][nex]<
        dp[i + 1][nex] = dp[i + 1][nex] % mod;
        return;
    }
    if ((state&(1 << (j))) >0) {
        dfs(i, j + 1, state, nex);
    }
    if ((state&(1 << (j))) == 0) {
        dfs(i, j + 1, state, (nex | (1 << (j))));
    }
    if ((state&(1 << (j))) == 0 && (j + 11 <<( j + 1))) == 0)) {
        dfs(i, j + 2, state, nex);
    }
}
int main()
{
    memset(dp, 0, sizeof(dp));
    scanf("%d%d", &n, &m);
    dp[1][0] = 1;
    //int t = (3 & (1 << (1)));
    //cout <
    for (int i = 1; i <= m; i++) {
        for (int j = 0; j <(1 << (n)); j++) {
            dfs(i, 0, j, 0);
        }
    }
    cout << dp[m + 1][0] << endl;
    return 0;
}

你可能感兴趣的:(状压dp)