矩阵计数(蓝桥杯 2019 国赛)

题目描述

一个 N \times MN×M 的方格矩阵,每一个方格中包含一个字符 O 或者字符 X。

要求矩阵中不存在连续一行 3 个 X 或者连续一列 3 个 X。

问这样的矩阵一共有多少种?

输入描述

输入一行包含两个整数 N, M\ (1 \leq N,M \leq 5)N,M (1≤N,M≤5)。

输出描述

输出一个整数代表答案。

输入输出样例

示例

输入

2 3

输出

49

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

思路

首先进行初始化,将每一行符合条件的给筛出来,比如样例2 3,2行3列,一行3个

0 0 0        0 0 1        0 1 0        0 1 1

1 0 0        1 0 1        1 1 0        1 1 1

1 1 1不符合条件

之后再进行dp,通过&将行与行之间符合条件的给筛出来

#include 
#include 
#include 
using namespace std;
const int N = 7;
int n, m, res;
int st[1 << N];
int f[1 << N][1 << N][1 << N];

// 1为X 0为O 一列或一行不出现连续三个X
bool check(int num)
{
    int cnt = 0; // num的二进制中1的个数
    while (num)
    {
        if (num & 1)
            cnt++;
        else
            cnt = 0;
        if (cnt >= 3) // 如果num中1的个数大于1,例如7(111)则列不能为7
        {
            return true;
        }
        num >>= 1;
    }
    return false;
}
void init()
{
    res = 0;
    for (int i = 0; i < (1 << m); ++i)
    {
        if (!check(i))
        {
            st[res++] = i;
        }
    }
}

void dp()
{
    // f[i][j][k]的含义为,第i行的状态为j,第i-1行的状态为k;
    // 初始状态第0行的状态什么也没有,所以为1;
    f[0][0][0] = 1;
    for (int i = 1; i <= n + 2; ++i)
    {
        for (int j = 0; j < res; ++j)
            for (int k = 0; k < res; ++k)
            {
                for (int l = 0; l < res; ++l)
                {
                    // 位运算的一个小技巧,比如
                    // 1(001)
                    // 3(011)
                    // 7(111)
                    // 三个数同时按位与得到1,即末尾的1
                    if (j & k & l)
                        continue;
                    f[i][j][k] += f[i - 1][l][j];
                }
            }
    }
}

int main()
{
    memset(st, 0, sizeof(st));
    cin >> n >> m;
    init();
    dp();
    cout << f[n + 2][0][0];
}

 

你可能感兴趣的:(蓝桥杯,矩阵,c++)