程序员的算法趣题Q68: 异性相邻的座位安排(1)

目录

1. 问题描述

2. 解题分析

3. 代码及测试

4. 后记


1. 问题描述

  

        这道题的描述应该是有问题的(不知道是原文的问题还是翻译的问题)。

        前面的描述中提到“前后左右的座位全是异性”和NG示例中的“前后左右全是同性”两种情况。问题中所要求满足的“上述条件”是什么呢?仅从上下文来看第一感当然是说“前后左右的座位全是异性”。但是仔细一想就知道这个不对,每个座位的“前后左右的座位都是异性”的安排情况只有两种。

        “前后左右的座位全是异性”和“前后左右全是同性”的两种极端情况之间还有巨大的灰色空间。问题的原意应该是指满足“任何一个座位的前后左右不全是同性(或至少有一个异性)”的情况吧?

2. 解题分析

        先考虑一个基本方案。

        从搜索方式来说,这个问题与前面的Q32和Q59等题有类似之处。只需要基于Q32或Q59的基本框架略作修改即可。

        要点说明:

  1. 与Q32, Q59一样,逐行扫描,每次向右移一格。右边到头即移到下一格。到达最下边的围栏行则表明已经完成一次搜索,找到一个合规的安排方案
  2. “违规检查”只需要针对当前座位的左边座位和上边座位,这是因为扫描是向右、下方向进行的,当前座位的右边和下边还没有安排人,所以右边座位和下边座位肯定还没有违规
  3. 最后还必须满足男生和女生人数都必须相等

  

3. 代码及测试

# -*- coding: utf-8 -*-
"""
Created on Tue Oct 19 07:39:48 2021

@author: chenxy
"""

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

H = 5 # Height, vertical
W = 6 # Width,  horizontal

# seats initialization, with a guard band surrounding the original seats
# The guard band is initialized to '-1' to simplify the judgement processing.
seats = np.zeros((H+2, W+2))
seats[0,:] = -1
seats[H+1,:] = -1
seats[:,0] = -1
seats[:,W+1] = -1

count = 0

def isNG(h,w):
    if seats[h,w] == -1:
        return False
    return (seats[h+1,w]==seats[h,w] or seats[h+1,w]==-1) and \
           (seats[h-1,w]==seats[h,w] or seats[h-1,w]==-1) and \
           (seats[h,w+1]==seats[h,w] or seats[h,w+1]==-1) and \
           (seats[h,w-1]==seats[h,w] or seats[h,w-1]==-1) 
    

def arrange_seat(h,w, boy, girl)->int:
    '''
    Parameters
    ----------
    (h,w) : The current exploration point. 
            h represents row index, w represents col index.
    Returns: int
        The number of total arrangement starting from the point (h,w), together 
        with the current seats status, which is a global variable

    '''        
    global count
    # print('h = {0}, w = {1}'.format(h,w))
    if   h == H + 1:
        if boy == girl:
            count = count + 1
        # print(seats)    
    elif w == W + 1: # Go to the next row.
        # Reach the right boundary, go to explore the next row from the left 
        arrange_seat(h+1, 1, boy, girl)
    # elif seats[h,w] > 0: 
    #     # This grid has been occupied, move to the right one
    #     arrange_seat(h, w+1)
    else:
        # Try to arrange boy to the current seat(h,w)
        seats[h,w] = 1
        if not (isNG(h-1,w) or isNG(h,w-1) or isNG(h,w)):
            arrange_seat(h,w+1, boy+1, girl)            
        seats[h,w] = 0
        # Try to arrange girl to the current seat(h,w)
        seats[h,w] = 2
        if not (isNG(h-1,w) or isNG(h,w-1) or isNG(h,w)):
            arrange_seat(h,w+1, boy, girl+1)            
        seats[h,w] = 0
                                    
tStart = time.perf_counter()
arrange_seat(1, 1, 0, 0)
tCost  = time.perf_counter() - tStart
print('count = {0}, tCost = {1:6.3f}(sec)'.format(count,tCost))  

运行结果:        

        [3,4]: count = 354, tCost =  0.014(sec) 

        [4,5]: count = 34874, tCost =  1.649(sec)

        [5,6]: count = 13374192, tCost = 803.130(sec)

4. 后记

        跟昨天的Q69一样,给出一个功能正确的方案并不难,但是运行太慢了!所以这些问题的难点在于如何提高运行效率,比如说书中所提示的剪枝,还有memoization等啊?容我再想一想。。。

        上一篇:Q67: 不挨着坐是一种礼节吗?

        下一篇:Q69: 蓝白歌会(1)     

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

笨牛慢耕

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

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

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

打赏作者

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

抵扣说明:

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

余额充值