程序员的算法趣题Q46: 唯一的OX序列

本文介绍了如何解决一个关于N×N矩阵中O和X排列的问题,通过将O和X转化为二进制矩阵并使用哈希表计数signature的方法,计算出满足条件的排列数量。作者提供了Python代码实现,并讨论了可能的优化方案,如位操作和排除特定矩阵。在N=4的情况下,得到了6902种排列。文章还提及后续的优化和相关算法趣题系列。
摘要由CSDN通过智能技术生成

目录

1. 问题描述

2. 解题分析

3. 代码及测试

4. 后记


1. 问题描述

         当n=4时,像上述例子一样,根据统计结果重新排列O和X的位置,只有一种排列方式的O和X的排列一共有多少种呢?

2. 解题分析

        因为是对O计数,可以用1代表O,用0代表x,这样原矩阵就转化为一个二进制矩阵。

        以下采用暴力搜索法。

        对N*N的所有可能的二进制矩阵进行N行和N列的,所得的2*N个值形成的排列{r1_sum, r2_sum, …,rN_sum, c1_sum, c2_sum, …, cN_sum }构成这个矩阵的signature。然后查询值对应唯一的矩阵的signature的个数。可以在遍历所有矩阵时,对各种signature出现的次数进行计数,最后计数值为1的signature个数即为所求结果。signature出现的次数可以用哈希表来存储,在python中就是dict()。

        N*N的所有可能的二进制矩阵种类数为 , N=4时为65536,随着N增大急剧增大。

        算法流程如下所示:

 

3. 代码及测试

# -*- coding: utf-8 -*-
"""
Created on Wed Sep 29 07:51:03 2021

@author: chenxy
"""

import sys
import time
import datetime
import math
# import random
from   typing import List
# from   queue import Queue
from   collections import deque
import itertools as it
import numpy as np

N = 4
sigCount = dict()

tStart = time.perf_counter()
for node in it.product([0,1],repeat=N**2):
    a = np.array(node).reshape(N,N)
    # print(a)
    col_sum = np.sum(a,axis=0)
    row_sum = np.sum(a,axis=1)
    sig = tuple(np.concatenate((col_sum,row_sum)))
    if sig in sigCount:
        sigCount[sig] += 1
    else:
        sigCount[sig]  = 1

count = 0
for key in sigCount:
    if sigCount[key] == 1:
        count += 1
tCost = time.perf_counter() - tStart

print('N = {0}, count={1}, tCost = {2:6.3f}(sec)'.format(N,count,tCost))   

        运行结果:N = 4, count=6902, tCost =  0.891(sec)

4. 后记

        有两个可能改进方案:

  1. 用二进制的形式来表示矩阵,以位操作的方式实现行和以及列和计算
  2. 矩阵中任意一个子矩阵的4个顶点按对角线分为两组,一组为全0、另一组为全1的情况下,很明显可以构成出和它所对应相同的signature的不同矩阵,因此可以排除在搜索范围之外

        以后回头来补上这些改进解。

        上一篇:Q45: 排序交换次数的最少化        

        下一篇:程序员的算法趣题Q47: 格雷码循环

        本系列总目录参见:程序员的算法趣题:详细分析和Python全解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨牛慢耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值