程序员的算法趣题Q67: 不挨着坐是一种礼节吗?

Posted 笨牛慢耕

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序员的算法趣题Q67: 不挨着坐是一种礼节吗?相关的知识,希望对你有一定的参考价值。

目录

1. 问题描述

2. 解题分析

2.1 基本思路

2.2 动态规划

2.3 算法流程

3. 代码及测试

4. 后记


1. 问题描述

        注意,本问题不区分人,只考虑各个座位被占用的不同顺序的个数。 

2. 解题分析

2.1 基本思路

        每个人选座位时,首先看有没有“超空位”(两边都没有挨着人的空位暂称为“超空位”),如果有则优先从“超空位”中选取。如果没有超空位,则从空位中任选一个坐下(空位是一定有的,因为人数和座位数是相等的)。

        由于车厢中的作为安排方式(对面两排),两头两位的座位有一边是一定不挨着人的。如何表达才最方便于实现呢?

        借用棋盘问题中的围栏思想,将两排座位排成一排,但是两头和中间各插入一个dummy座位(不能坐人),这样连同dummy座位总共有15个,可以表达为长度为15的数组。Dummy座位置为”-1”表示不能坐人,正常座位初始化为“0”,被人占据了则复制为“1”。这样,判断一个正常座位是否为“超空位”,只要看它本身是否为0且两边都不是1(即为“0”或者“-1”)。

2.2 动态规划

        考虑已经有k个座位被占了,从当前状态出发往后的剩下的(12-k)个座位被占的顺序数只与当前这个k个座位被占的状态有关,而与它们被占的顺序无关。因此这个可以用动态规划的策略来解决。本题考虑用top-down的方式(递归+memoization)来实现动态规划策略。

2.3 算法流程

        算法流程如下:

3. 代码及测试

# -*- coding: utf-8 -*-
"""
Created on Sun Oct 17 10:52:39 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

memo = dict()

def isFull(pos):
    return np.all(pos[1:7]) and np.all(pos[8:14])

def search(pos):
    
    if tuple(pos) in memo:
        return memo[tuple(pos)]
    if isFull(pos):
        return 1
    
    cnt = 0
    hasSuperEmpty = False
    # Search super empty seat
    for k in [1,2,3,4,5,6,8,9,10,11,12,13]:
        if pos[k]==0 and pos[k-1]!=1 and pos[k+1]!=1:
            pos[k] = 1
            cnt = cnt + search(pos)
            hasSuperEmpty = True
            pos[k] = 0
        
    if not hasSuperEmpty:
        for k in [1,2,3,4,5,6,8,9,10,11,12,13]:
            if pos[k]==0:
                pos[k] = 1
                cnt = cnt + search(pos)
                pos[k] = 0
    memo[tuple(pos)] = cnt
    return cnt

N   = 12 # Can't modify currently
pos = np.zeros(N+3)
pos[N//2+1] = -1
pos[N+2]    = -1

tStart = time.perf_counter()
count = search(pos)
tCost  = time.perf_counter() - tStart
print('count = {0}, tCost = {1:6.3f}(sec)'.format(count,tCost))      

        运行结果:count = 14100480, tCost =  0.032(sec) 

4. 后记

        轻松搞定。

        跳过了前面一些题目先做这道,是因为浏览了一下“高级篇”中的题目,大多数题目想2~3分钟感觉没有头绪,先捏这种一看就觉得“顺眼”的软柿子捏一捏^-^。这种策略对于学习很重要,盲目地死磕一道题目花费太久时间容易产生挫折感从而打击学习的积极性。有些问题一时没有头绪,放在脑袋里供闲暇时间想一想说不定更容易突然就有什么灵感。。。

        上一篇:Q66: 设计填字游戏

        下一篇:Q68: 异性相邻的座位安排

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

以上是关于程序员的算法趣题Q67: 不挨着坐是一种礼节吗?的主要内容,如果未能解决你的问题,请参考以下文章

程序员的算法趣题Q22: 不缠绕的纸杯电话

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

程序员的算法趣题Q29: 合成电阻的黄金分割比

程序员的算法趣题Q37: 翻转7段码

程序员的算法趣题Q43: 让玻璃杯水量减半

程序员的算法趣题pdf