蓝桥杯国赛 矩阵计数(python-状压DP)
题目描述
一个 N× M 的方格矩阵,每一个方格中包含一个字符 O 或者字符 X。
要求矩阵中不存在连续一行 3 个 X 或者连续一列 3 个 X。
问这样的矩阵一共有多少种?
输入描述
输入一行包含两个整数 N, M (1≤ N,M ≤ 5)。
输出描述
输出一个整数代表答案。
输入输出样例
示例
输入
2 3
输出
49
思路 🤔
这道题是利用状态压缩DP进行一个预测的,首先,把方格中的字符 ‘0’ 看成数字 0,字符 ‘X’ 看成数字 1。把每一行看成一个 m 位的二进制数,例如一行字符 “00X0X00X0X” 对应二进制数 “0010100101”。那么一行数字就有 2^m 种情况。
我们设计一个列表row,用来存储”合法的”行,所谓合法的行就是指这一行中不存在一行连续的 3 个 X。
首先我们定义一个三维数组,对于d p [ i ] [ j ] [ k ]来说,它表示第i行的合法状态时j,它前一行的合法状态是k时,符合状态的矩阵有多少个。合法状态来说,也就是考虑当前行和前一行的状态,如果row[j]&row[k]&row[p]==1, 说明这 3 行没有一列上是3个 1,即这 3行是一种合法状态。
符合当前行的合法状态的矩阵数就等于符合之前一行的所有合法状态§的和,如此递推到最后一行。所以在最后,我们计算的是,最后两行合法的状态有多少个,最后进行加和就可以得出最后的结果。
代码 💻
# https://www.lanqiao.cn/problems/246/learning/ import os import sys n,m = map(int,input().split()) L = 1<<m def judge(x): c = 0 for _ in range(L): if x&1 == 0: c = 0 else: c += 1 if c == 3: return False x >>= 1 return True row = [] for i in range(L): if judge(i): row.append(i) # dp[i][j][k],表示第i行的合法状态时j,它前一行的合法状态是k时,符合状态的矩阵有多少个 # dp = [[[0]*L for _ in range(L)] for _ in range(n)] dp = [[] for _ in range(n)] for i in range(n): dp[i] = [[0]*L for _ in range(L)] l = len(row) for i in range(l): dp[0][row[i]][0] = 1 # 枚举前i行 for i in range(1,n): for j in range(l): for k in range(l): for p in range(l): if row[j] & row[k] & row[p] == 0: dp[i][row[j]][row[k]] += dp[i-1][row[k]][row[p]] ans = 0 for i in range(l): for j in range(l): ans += dp[-1][row[i]][row[j]] print(ans)