棋盘覆盖问题与可视化代码演示

Posted Huterox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了棋盘覆盖问题与可视化代码演示相关的知识,希望对你有一定的参考价值。

前言

不知不觉这篇博客是我在CSDN公开发布的第200篇博客的,嘚瑟一波~

棋盘覆盖

今天要做的是一个棋盘覆盖的玩意,这个呢,也是某位老师留的一个小问题,那么这个就让小爷来终结吧~

描述

这个很简单,就是那啥有一个棋盘,然后这个棋盘是 2^k * 2^k 大小的,然后有一个障碍物,现在要你再不覆盖障碍物的情况下,去使用四种骨牌去覆盖棋盘。如下图:

题目就是这个题目,思路也是典型的那个分治。当然那个这个也是说一下这个问题,怎么个分治法,策略是什么。
来先看看我们最后实现的效果

思路

说到这个分治,我们必然要用到递归,说到递归我们必然要最起码讨论两种情况,开始和结束状态。
搞清楚开始状态有利于编写流程,搞清楚结束状态有利于编写结束位置。

开始

都说了,分治,那么必然是问题划分,分解子问题,对于一个2x2的棋盘,我们只需要考虑阻碍点在哪,然后把走位点覆盖那么就是我们想要的效果,例如这样。

所以对于一个大棋盘我们要考虑的就是划分呀,把一张大棋盘一直划分,每次划分的时候构建相同的子问题。

子问题构建

问了来了,子问题是啥,子问题就是一个区域内长得像上图的区域,然后在那种区域内求解问题。所以我们怎么干,这样干。

结束

这个时候我们看到最小问题的情况下(最小子问题),当2x2的时候,我们按照我们的中间过程,我们会打周围的都覆盖,之后再划分,那个时候都变成1x1的格子了,这个时候显然就没有必要继续分割了,退出。

初步编写代码

这次的话是采用python进行编写。因为考虑到那个要那啥图形化嘛,是吧,而且这次也是使用python在一年前提出的新的语法特性来玩玩。
这里的话也是现在我们的控制台输出程序。不过这里要注意保存一下我们的那个覆盖的方式。

TIMES = 1 #放置的次数

ROUTERS = dict()

def showBord(bord:list):
    for rows in bord:
        for j in rows:
            print(j,end=" ")
        print("")


def AddRouter(key:int,value:tuple):
    global ROUTERS
    if(ROUTERS.get(key)):
        temp = ROUTERS.get(key)
        temp.append(value)
    else:
        ROUTERS[key] = list()
        temp1 = ROUTERS.get(key)
        temp1.append(value)





def ChessBord(tr:int,tc:int,dr:int,dc:int,size:int,BORD:list):
    global TIMES,ROUTERS
    #不断分割,知道size为1
    if(size == 1):
        return
    T = TIMES #当前覆盖的玩意
    TIMES +=1

    s = int(size/2) #开始做分割

    #开始四个方位去判断那个有木有方格子,没有就继续分割,如果没有那么就在那边标记一下
    #左上角
    if(dr<tr+s and dc<tc+s):
        ChessBord(tr,tc,dr,dc,s,BORD)
    else:
        BORD[tr+s-1][tc+s-1] = T
        AddRouter(T,(tr+s-1,tc+s-1))
        ChessBord(tr,tc,tr+s-1,tc+s-1,s,BORD)

    #右上角
    if (dr < tr + s and dc >= tc + s):
        ChessBord(tr, tc+s, dr, dc, s, BORD)
    else:
        BORD[tr + s - 1][tc + s] = T
        AddRouter(T,(tr + s - 1,tc + s))
        ChessBord(tr, tc+s, tr + s , tc + s - 1, s, BORD)

    #左下角
    if (dr >= tr + s and dc < tc + s):
        ChessBord(tr+s, tc, dr, dc, s, BORD)
    else:
        BORD[tr + s][tc + s - 1] = T
        AddRouter(T,(tr + s,tc + s - 1))
        ChessBord(tr+s, tc, tr + s, tc + s - 1, s, BORD)

    #右下角
    if (dr >= tr + s and dc >= tc + s):
        ChessBord(tr+s, tc+s, dr, dc, s, BORD)
    else:
        BORD[tr + s ][tc + s ] = T
        AddRouter(T,(tr + s ,tc + s ))
        ChessBord(tr + s, tc + s, tr + s, tc + s, s, BORD)


if __name__ == '__main__':

    SIZE = int(input("please input your size (the size must be 2^k:"))
    dr = int(input("please input the barrier row"))
    dc = int(input("please input the barrier column"))
    BORD = [[0 for x in range(SIZE)] for i in range(SIZE)]  # 初始化棋盘

    ChessBord(0,0,dr,dc,SIZE,BORD)
    showBord(BORD)
    for i in ROUTERS.keys():
        print(ROUTERS.get(i))


那个0就是我们一开始的障碍物。

图形化升级

接下来要做的就是图像话升级。
这个也好办,我这里直接使用海龟绘图

棋盘绘制

from turtle import Turtle

import turtle

Size = 8
turtle.screensize(800,800,"white")

class Board(Turtle):
    def __init__(self,size,dr,dc):

        Turtle.__init__(self)
        self.shape('square')
        self.hideturtle()
        self.speed(30)
        self.width = 600
        self.height = 800
        self.size = size

        self.boxsize = 50

        self.startx = -int((self.size * self.boxsize)/2)
        self.starty = int((self.size * self.boxsize)/2)


        self.rebound()

        self.drawboard() #绘制棋盘
        self.drawfill("red",dr,dc)
        # self.drawfill("aqua",0,5)

    def drawrowline(self):

        for i in range(self.size+1):
            self.pendown()
            self.forward(self.size*self.boxsize)
            self.penup()
            self.goto(self.startx,self.starty-((i+1)*self.boxsize))

        self.rebound()

    def drawcolumnline(self):
        self.right(90) #调换方向
        for i in range(self.size+1):
            self.pendown()
            self.forward(self.boxsize*self.size)
            self.penup()
            self.goto(self.startx+self.boxsize*(i+1),self.starty)
        self.rebound()

    def drawboard(self):
        self.drawrowline()
        self.drawcolumnline()
        self.rebound()

    def move(self,UI_x,UI_y):
        self.penup()
        self.goto(UI_x,UI_y)
    def transforuipos(self,row,column):

        #负责把那个矩阵上面的坐标换算为在UI界面的坐标
        UI_y = (self.starty - row*self.boxsize)
        UI_x = self.startx + self.boxsize*column

        return UI_x,UI_y
    def drawfill(self,color,row,column):
        UI_x,UI_y= self.transforuipos(row,column)
        self.move(UI_x,UI_y)

        #给方格上色
        self.pendown()
        self.begin_fill()
        self.fillcolor(color)
        for i in range(4):
            self.forward(self.boxsize)
            self.right(90)
        self.end_fill()
        self.rebound()

    def rebound(self):
        #复原
        if(self.isdown()):
            self.penup()
        self.home()
        self.goto(self.startx, self.starty)  # 起始点

if __name__ == '__main__':
    board = Board(8,2,2)

    turtle.mainloop()

这里有个坑,那就是那个goto()这个是按照那个中心坐标来算的,刚刚调了小半天,坑死我了。

整合

现在可以开始整合我们的代码了。

整合算法


class Algorithm:
    def __init__(self):
        self.TIMES = 1
        self.ROUTERS = dict()

    def showBordinConsole(self,bord: list):
        for rows in bord:
            for j in rows:
                print(j, end=" ")
            print("")

    def AddRouter(self,key: int, value: tuple):

        if (self.ROUTERS.get(key)):
            temp = self.ROUTERS.get(key)
            temp.append(value)
        else:
            self.ROUTERS[key] = list()
            temp1 = self.ROUTERS.get(key)
            temp1.append(value)

    def ChessBord(self,tr: int, tc: int, dr: int, dc: int, size: int, BORD: list):

        # 不断分割,知道size为1
        if (size == 1):
            return
        T = self.TIMES  # 当前覆盖的玩意
        self.TIMES += 1

        s = int(size / 2)  # 开始做分割

        # 开始四个方位去判断那个有木有方格子,没有就继续分割,如果没有那么就在那边标记一下
        # 左上角
        if (dr < tr + s and dc < tc + s):
            self.ChessBord(tr, tc, dr, dc, s, BORD)
        else:
            BORD[tr + s - 1][tc + s - 1] = T
            self.AddRouter(T, (tr + s - 1, tc + s - 1))
            self.ChessBord(tr, tc, tr + s - 1, tc + s - 1, s, BORD)

        # 右上角
        if (dr < tr + s and dc >= tc + s):
            self.ChessBord(tr, tc + s, dr, dc, s, BORD)
        else:
            BORD[tr + s - 1][tc + s] = T
            self.AddRouter(T, (tr + s - 1, tc + s))
            self.ChessBord(tr, tc + s, tr + s, tc + s - 1, s, BORD)

        # 左下角
        if (dr >= tr + s and dc < tc + s):
            self.ChessBord(tr + s, tc, dr, dc, s, BORD)
        else:
            BORD[tr + s][tc + s - 1] = T
            self.AddRouter(T, (tr + s, tc + s - 1))
            self.ChessBord(tr + s, tc, tr + s, tc + s - 1, s, BORD)

        # 右下角
        if (dr >= tr + s and dc >= tc + s):
            self.ChessBord(tr + s, tc + s, dr, dc, s, BORD)
        else:
            BORD[tr + s][tc + s] = T
            self.AddRouter(T, (tr + s, tc + s))
            self.ChessBord(tr + s, tc + s, tr + s, tc + s, s, BORD)

    def GetRouters(self,SIZE,dr,dc,show=False)->dict:
        BORD = [[0 for x in range(SIZE)] for i in range(SIZE)]  # 初始化棋盘
        self.ChessBord(0,0,dr,dc,SIZE,BORD)
        if(show):
            self.showBordinConsole(BORD)
        return self.ROUTERS


if __name__ == '__main__':
    algorithm= Algorithm()
    routers = algorithm.GetRouters(4,1,3,show=True)
    for i in routers.keys():
        print(routers.get(i),"-----",i)

整合UI

接下来就是整合我们的UI就好了,这里我们再搞一个控制代码


from Bord.BordPlace import Algorithm
from Bord.ShowDynamic import Board
import turtle
class ShowPlaceUI:
    def __init__(self,size,dr,dc):
        self.size = size
        self.dr = dr-1
        self.dc = dc-1
        self.algorithm = Algorithm()
        self.board = Board(self.size,self.dr,self.dc)
        self.colors = ["aqua","lime","yellow"]
    def run(self):

        routers = self.algorithm.GetRouters(self.size,self.dr,self.dc)
        # self.board.speed(10)
        for key in routers:
            points = routers.get(key)
            for point in points:
                color = self.colors[(key-1)%3]
                row,coloumn = point
                self.board.speed(100)
                self.board.drawfill(color,row,coloumn)

if __name__ == '__main__':

    showUi =  ShowPlaceUI(8,2,4)

    showUi.run()

    turtle.mainloop()


效果演示

以上是关于棋盘覆盖问题与可视化代码演示的主要内容,如果未能解决你的问题,请参考以下文章

「CH6801」棋盘覆盖

P3355 骑士共存问题最小点覆盖网络流24题

C++经典算法问题:棋盘覆盖问题(分治算法)!含源码示例

分治与递归-棋盘覆盖问题

棋盘覆盖问题——分治法——代码清晰易懂

计算机算法设计与分析之棋盘覆盖问题