蓝桥杯19国赛-矩阵计数
题目
一个N×M 的方格矩阵,每一个方格中包含一个字符 O 或者字符 X。
要求矩阵中不存在连续一行 3 个 X 或者连续一列 3 个 X。
问这样的矩阵一共有多少种?
输入描述
输入一行包含两个整数 N, M (1≤N,M≤5)。
输出描述
输出一个整数代表答案。
输入输出样例
示例
输入
2 3
输出
49
运行限制
- 最大运行时间:1s
-
最大运行内存: 256M
思路:
大佬的思路:(1条消息) 蓝桥杯系列 - 2019国赛 - 矩阵计数_notmuch的博客-CSDN博客_矩阵计数蓝桥杯
首先,把方格中的字符 ‘0’ 看成数字 0,字符 ‘X’ 看成数字 11。把每一行看成一个 m 位的二进制数,例如一行字符 “00X0X00X0X” 对应二进制数 “0010100101”。那么一行数字就有 2^m 种情况。
我们设计一个列表stateAllowed,用来存储”合法的”行,所谓合法的行就是指这一行中不存在一行连续的 3 个 X。
定义状态:
dp[i][j][k],表示第i行的合法状态时j,它前一行的合法状态是k时,符合状态的矩阵有多少个。
状态转移方程:
我们考虑当前行和之前两行的状态,如果 j & k & p = 0
,说明这 3 行没有一列上是3个 1,即这 3行是一种合法状态。符合当前行的合法状态的矩阵数就等于符合之前一行的所有合法状态(p)的和,如此递推到最后一行。
if j&k&p==0: dp[i][j][k]+=dp[i-1][k][p]
计算结果:
倒数第三行和前面的多种组合情况已经计算过了,所以我们只需要累加倒数最后两行的所有合法状态即可
ans=0for i in stateAllowed: ans+=sum(dp[N-1][i])
代码:
N,M=map(int,input().split())numState=2**MstateAllowed=[]for i in range(numState): cnt,flag=0,False temp=i while temp: if temp&1: cnt+=1 else: cnt=0 if cnt>=3: flag=True break temp>>=1 if not flag: stateAllowed.append(i)dp=[[[0 for _ in range(numState)] for _ in range(numState)] for _ in range(N)]for i in stateAllowed: dp[0][i][0]=1for i in range(N): for j in stateAllowed: for k in stateAllowed: for p in stateAllowed: if j&k&p==0: dp[i][j][k]+=dp[i-1][k][p]ans=0for i in stateAllowed: ans+=sum(dp[N-1][i])print(ans)