用图和栈的深度遍历思想解决组合全部序列的输出

例子:
有6个颜色各不相同的水桶,其桶身和桶盖颜色相同,现在将桶身和桶盖随机打乱组合,求全部桶盖和桶身都不匹配的组合有多少种?打印所有组合。

算法思想:
不同桶盖和桶身一对一匹配,但是颜色不能一样。我们建立一个列表:里面的元素值表示桶身元素的位置表示桶盖
我们对桶身进行遍历,假如桶身元素值等于它的这个位置,不能取;假如不等于而且以前没有被用过,它是可以用的,我们把它的值加到列表里面,列表的长度也加1.假如列表的长度变成水桶总数,输出目前列表里面的值。
删除元素的情况有两个:

  1. 现在的元素满了需要删除列表最后一个元素
  2. 现在的元素不能满足题目要求,组不了匹配序列,也删除列表最后一个元素。(不用担心删的不够,因为我们是递归调用,所以一层一层删回去直到满足条件)

我们采用图的深度遍历方法,设置访问矩阵表示桶身的使用情况。下面是所有代码可以运行,想来看解释的话在后面。

class ColorStack:
    color_list = []
    length = 0

    def __init__(self, length=0):
        self.length = length

    def push(self, x: int):
        self.color_list.append(x)
        self.length += 1

    def pop(self):
        if self.length <= 0:
            return -1
        var = self.color_list.pop()
        self.length -= 1
        return var


count = 0


def count_combinations():
    for i in range(6):
        color = ColorStack()
        visited_color = [0 for i in range(6)]
        if i != 0:
            visited_color[i] = 1
            color.push(i)
            DFS_color(color, visited_color)


def DFS_color(color=ColorStack(), visited_color=[]):
    for j in range(6):
        if color.length < 6:
            if visited_color[j] == 0 and (color.length - 1) != j:
                visited_color[j] = 1
                color.push(j)
                DFS_color(color, visited_color)
        if color.length == 6:
            print(color.color_list)
            global count
            count += 1
            break
    var = color.pop()
    visited_color[var] = 0


if __name__ == '__main__':
    count_combinations()
    print(count)

全部代码写完了,假如你想输出文字,在函数

def DFS_color(color=ColorStack(), visited_color=[]):

if color.length == 6:
    print(color.color_list)

变一下对映关系,元素的值表示桶身,顺序表示桶盖,color.color_list就是类似[1,2,3,4,5,0]这样的值

下面是解释————————————————————————
我们定义了一个类ColorStack用来存颜色种类,count表示组合的所有数量

def count_combinations():
    for i in range(6):
        color = ColorStack()
        visited_color = [0 for i in range(6)]
        if i != 0:
            visited_color[i] = 1
            color.push(i)
            DFS_color(color, visited_color)

元素的值表示桶身,顺序表示桶盖)我们想遍历所有的情况,for i in range(6) ,这个就表示让桶盖子匹配桶身,假如第一个桶盖子和桶身颜色不一样就能继续,第一个桶盖子有5种匹配的可能,这样就包含了所有序列。

def DFS_color(color=ColorStack(), visited_color=[]):
    for j in range(6):
        if color.length < 6:
            if visited_color[j] == 0 and (color.length - 1) != j: # 匹配成功
                visited_color[j] = 1
                color.push(j) # 进栈
                DFS_color(color, visited_color) # 遍历下一个桶盖子
        if color.length == 6:
            print(color.color_list)
            global count # 统计不同组合数量
            count += 1
            break
    var = color.pop() 
    visited_color[var] = 0

这个是深度遍历内部的详细过程,visited_color表示桶盖子的有没有匹配成功,1表示匹配成功,0表示没有匹配成功,假如现在color.length<6,表示没完全匹配完,需要继续匹配。

break

break是因为现在的序列已经满足,所以要跳出循环,因为你也没元素能用了

 var = color.pop() 
 visited_color[var] = 0

这里之所以放在for循环外面一方面是因为元素不能用了,另一方面假如你 j 变成 6了,在现有元素下你已经得不到符合要求的序列了,所以要出栈,让这个位置的桶盖重新变得能用,回退到上一层。
结果在下面:

D:\design_project\python_project\Scripts\python.exe D:/design_project/python_project/text.py
[1, 2, 0, 3, 4, 5]
[1, 2, 0, 4, 5, 3]
[1, 2, 0, 5, 4, 3]
[1, 2, 3, 0, 4, 5]
[1, 2, 3, 4, 0, 5]
[1, 2, 3, 4, 5, 0]
...

一共256种,有什么问题或者错误的地方大家可以互相交流一下。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值