数据结构与算法分析1.2 Python采用栈的回溯解决四色问题

本文介绍了一种使用链栈实现的图着色问题解决方案,通过邻接矩阵存储图中关系,并利用回溯算法避免颜色冲突。在回溯过程中,采用了两种策略:存储不可用颜色的字典和随机颜色选择,以解决颜色分配的死锁问题。这种方法虽然会占用更多存储空间,但能确保找到有效的颜色分配方案。此外,文章还探讨了优化方法,如随机化颜色选择,以减少运行时间。

 如图所示:

解决代码如下:

import numpy as np


class Node:
    def __init__(self, data, next=None):
        self.data = data
        self.next = next


# 创建链栈
class Stack:
    def __init__(self):
        self.top = None
        self.size = 0

    # 判断栈是否非空
    def isEmpty(self):
        if self.top == None:
            return True
        else:
            return False

    # 将数据存入栈
    def Push(self, data):
        NewNode = Node(data)

        if self.top == None:
            self.top = NewNode
        else:
            NewNode.next = self.top
            self.top = NewNode
        self.size += 1

    # 删除最后进来的数据
    def Pop(self):
        if self.isEmpty():
            print("栈空无法出栈")
            return -1
        else:
            temp = self.top
            self.top = temp.next
            self.size -= 1
            return temp.data

    # 获取栈中数组长度
    def getLength(self):
        return self.size

    # 遍历栈
    def Travel(self):
        if self.isEmpty():
            print("栈空,无法遍历")
            return -1
        else:
            curse = self.top
            while curse != None:
                print(curse.data, end='')
                curse = curse.next
            print("")

    # 获取栈中某一序号的元素
    def getElement(self, position):
        if self.isEmpty():  # 栈空
            print("栈空,无法遍历")
            return -1
        elif position < 0 or position > self.getLength():  # 下标越界
            print("位置越界")
        else:
            curse = self.top
            pos = self.getLength() - 1  #由于对应的坐标从0开始,因此需要-1
            while position != pos:  #遍历,当栈的长度-1=位置坐标时即为对应的元素
                curse = curse.next
                pos -= 1
            return curse.data

#创建邻接矩阵存储图中关系
Map = np.mat("0,1,1,1,1,1,0;1,0,0,0,0,1,0;1,0,0,1,1,0,0;1,0,1,0,1,1,0;1,0,1,1,0,1,0;1,1,0,1,1,0,0;0,0,0,0,0,0,0")
MapColor = Stack()

#获取图中与某一地区相邻的地区坐标
def getPosition(CityNum):
    list0 = []
    for i in range(CityNum):
        if Map[CityNum, i] == 1:
            list0.append(i)
    return list0 #返回与该地区相邻的地区坐标构成的数组

#颜色组
ColorList = ['pink', 'yellow', 'red', 'green']

#由于回退时需要避免再次得到该种颜色,因此需要创建一个对象接受该地区对应的不可使用的元素
dic = {}
for i in range(7):  #初始化字典为空
    dic[i] = []


#赋色
def giveColor(CityNum, list):
    ColorNum = 0    #颜色序号
    list1 = getPosition(CityNum)    #该地区相邻地区的序号
    list2 = []
    for num in list1:
        list2.append(MapColor.getElement(num))  #该地区相邻地区的颜色(只考虑下半矩阵)
    while ColorNum < 4:
        if ColorList[ColorNum] in list2 or ColorList[ColorNum] in list: #若颜色与相邻地区重复 或 颜色不可使用,则尝试下一个颜色
            ColorNum += 1
        else:   #若可以使用,则压入栈直接进入下一个循环
            MapColor.Push(ColorList[ColorNum])
            break
    if ColorNum == 4:   #若序号为4,即四种颜色都不可用,则需要回溯,将已有的颜色出栈
        BanColor = MapColor.Pop()
        dic[CityNum] = []   #由于回溯,该地区对应的不可使用的颜色清空
        CityNum -= 1
        dic[CityNum].append(BanColor)   #不可使用的元素放入字典中存储
        return -1
    else:
        return 1


CityNum = 0
while CityNum < 7:
    s = giveColor(CityNum, dic[CityNum])
    CityNum = CityNum + s   #根据返回值决定为第几个地区涂色

for i in range(7):
    print("{}号地区涂的颜色是:{}".format(i+1,MapColor.getElement(i)))

        除此之外,解决回溯时不可采用颜色的问题,除了上述创建字典保存以外,还可以采用random函数,对于赋色时的顺序进行随机处理而不是顺序处理,这样也可以避免陷入死循环。对于第一种方法,其要求的存储空间较大;对于第二种方法,其运行时间更长。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值