SDUT2619 地板砖(状态压缩DP)

题目链接

题目原文:

地板砖

题目描述

利用假期时间,豆豆找个了临时工,帮有钱人家贴地板砖,假设房子的形状为 N x M 矩形,每个地板砖的大小为 1 x 1,且只有黑白两种颜色,这家人很奇怪,他们不喜欢房间中任何一个 2 x 2 的局部区域的 块地板砖的颜色一样。如果出现这种图案,豆豆就要重新贴,这当然难不倒豆豆,但爱学习的豆豆,想知道满足要求的法一共用多少种。

如下图所示:Figure 1.为满足要求的贴法,Figure 2.为不满足要求的贴法

输入

 

输入包含多组测试数据,对于每组测试数据:

输入只有两个正整数 NM(N  500, M  5),分别代表房间的长度和宽度。

输出

 

对于每组测试数据,输出满足要求的贴法总数,由于答案可能很大,所以需要对10007取余。

示例输入

2 2
3 3

示例输出

14
322

 

分析:

本题就是纯状态压缩DP,检查两状态是否矛盾没想到怎么用位运算,纯手工检查。

#include <iostream>  
#include <cstdlib>  
#include <cstring>  
#include <cstdio>  
  
using namespace std;  
  
const int r = 10007;  
long long dp[510][1<<5];  
int n, m;  
  
bool check(int i, int j){  
    int r1, r2;  
    int ok = -1;  
  
    for(int k=0; k<m; k++){  
        r1 = i % 2;  
        r2 = j % 2;  
        if(r1 == r2){  
            if(r1 == 1){  
                if(ok == 1) return 0;  
                else ok = 1;  
            }  
            else if(r1 == 0){  
                if(ok == 0) return 0;  
                else ok = 0;  
            }  
        }  
        else{  
            ok = -1;  
        }  
        i >>= 1; j >>= 1;  
    }  
    return 1;  
}  
  
int main(){  
  
    while(cin>>n>>m){  
        for(int i=0; i<(1<<m); i++) dp[1][i] = 1;  
  
        for(int i=2; i<=n; i++){  
            memset(dp[i], 0, sizeof(dp[i]));  
            for(int j=0; j<(1<<m); j++){  
                for(int k=0; k<(1<<m); k++){  
                    if(check(j, k)) dp[i][j] = (dp[i][j] + dp[i-1][k])%r;  
                }  
            }  
        }  
  
        long long ans = 0;  
        for(int i=0; i<(1<<m); i++){  
            ans += dp[n][i];  
        }  
        cout<<ans%r<<endl;  
  
    }  
    return 0;  
}  
原文地址:https://www.cnblogs.com/tanhehe/p/3072222.html