python三色旗

您所在的位置:网站首页 python单链表实现荷兰国旗问题 python三色旗

python三色旗

2024-06-18 07:32| 来源: 网络整理| 查看: 265

问题描述

        假设有一条绳子,上面有红、白、蓝三种颜色的旗子。开始时绳子上旗子的颜色并没有顺序,现要对旗子进行分类,并按照蓝、白、红的顺序排列。需要注意的是只能在这条绳子上进行移动,并且一次只能调换两个旗子,如何移动才能使旗子移动的次数最少。

        这个问题的本质就是说,在一个列表中随机分布着3种元素,元素的数量未知但有限,我们需要设计一个程序来交换这些元素的位置,使这个列表种的元素变成3部分,每部分中都是相同的元素。每次只能交换两个元素的位置,输出交换次数最少的操作步骤。

        在列表中交换两个元素的位置很简单,难的是操作步骤要最少。我们必须要分析一下,怎样操作得到的操作步骤会最少。首先我们知道旗子的总数、每种旗子的数量以及旗子最终的排布顺序,假设红色、白色、蓝色旗子各4个,最终排布顺序为蓝、白、红。

想一想我们要怎样操作才能使交换的步骤最少,我们应该根据最终顺序来判断某些旗子的顺序是否需要交换位置,例如第3个蓝旗、第10个红旗、第11个红旗都不需要交换位置。其次在交换旗子时我们应该把要交换的旗子先交换到它最终的区间,例如第2个白旗跟第5个蓝旗交换、第4个白旗跟第6个蓝旗交换、第7个红旗跟第9个白旗交换都能把它们换到各自的最终区间。最后我们再来交换剩余需要交换的旗子,如此操作就可以使操作步骤最少。

因此我们可以把交换步骤分为两类,第一类为互惠交换,第二类为自然交换。先执行互惠交换,再执行自然交换,可以使交换步骤最少。

设计交换程序

        根据上述描述,我们可以把交换程序分为两个部分,第一个部分为互惠交换,第二个部分为自然交换。

互惠交换

        互惠交换时我们需要先判断出各色旗子所在的区间,然后根据棋子的区间来判断是否需要交换,以及交换时要使两个旗子都放置到各自的最终区间。如果不能满足互惠交换的棋子就不交换,留给自然交换去处理。

flag = ["红", "白", "蓝", "白", "蓝", "蓝", "红", "蓝", "白", "红", "红", "白"] # 排序旗子 order = ["蓝", "白", "红"] # 最终顺序 # 互惠交换代码 range_list = [0] # 定义各色棋子区间列表 for i in order: range_list.append(flag.count(i)) # 先统计各色棋子的数量 for i in range(len(range_list)): if i > 0: range_list[i] = range_list[i - 1] + range_list[i] # 算出各色棋子在绳子上的区间 for i in range(len(order)): for n in range(range_list[i], range_list[i + 1]): # 按最终的棋子顺序输出棋子的区间 if flag[n] != order[i]: # 判断棋子是否属于此段区间 index = order.index(flag[n]) # 找出该棋子在颜色排布列表中的索引 if order[i] in flag[range_list[index]:range_list[index + 1]]: # 判断该区间颜色的棋子是否存在于可直接交换区间中 for m in range(range_list[index], range_list[index + 1]): # 逐个输出直接交换区间的棋子 if flag[m] == order[i]: # 判断棋子是否为直接交换的棋子 flag[n], flag[m] = flag[m], flag[n] # 交换棋子 print(f'{n + 1} 旗和 {m + 1} 旗交换位置') # 打印交换位置 print(flag) # 打印交换后的棋子顺序 break # 结束循环 自然交换

        自然交换时需要查看是否还有旗子没有归位到最终区间,如果有我们就把区间之外属于此区间的旗子交换到此区间,不需要做任何处理和思考,就是简单的交换。

for i in range(len(order)): for n in range(range_list[i], range_list[i + 1]): # 按最终的棋子顺序输出棋子的区间 if flag[n] != order[i]: # 判断棋子是否属于此段区间 for x in range(range_list[i + 1], range_list[-1]): # 循环输出该区间以外的棋子 if flag[x] == order[i]: # 判断棋子是否为该区间的棋子 flag[n], flag[x] = flag[x], flag[n] # 交换棋子 print(f'{n + 1} 旗和 {x + 1} 旗交换位置') # 打印交换位置 print(flag) # 打印交换后的棋子顺序 break # 结束循环 完整代码

        把互惠交换和自然交换结合起来,互惠交换在前,自然交换收尾。我们就能得到一个操作步骤最少的交换程序,完整代码如下:

flag_list = ["红", "白", "蓝", "白", "蓝", "蓝", "红", "蓝", "白", "红", "红", "白"] order_list = ["蓝", "白", "红"] def three_flag(flag, order): """ 三色旗问题 :param flag: 旗子列表 :param order: 颜色排布列表 :return: """ range_list = [0] for i in order: range_list.append(flag.count(i)) for i in range(len(range_list)): if i > 0: range_list[i] = range_list[i - 1] + range_list[i] for i in range(len(order)): for n in range(range_list[i], range_list[i + 1]): if flag[n] != order[i]: index = order.index(flag[n]) if order[i] in flag[range_list[index]:range_list[index + 1]]: for m in range(range_list[index], range_list[index + 1]): if flag[m] == order[i]: flag[n], flag[m] = flag[m], flag[n] print(f'{n + 1} 旗和 {m + 1} 旗交换位置') print(flag) break for i in range(len(order)): for n in range(range_list[i], range_list[i + 1]): if flag[n] != order[i]: for x in range(range_list[i + 1], range_list[-1]): if flag[x] == order[i]: flag[n], flag[x] = flag[x], flag[n] print(f'{n + 1} 旗和 {x + 1} 旗交换位置') print(flag) break three_flag(flag_list, order_list)

执行结果如下:

有了这个函数,3色旗、4色旗、5色旗,不管多少种颜色的旗子。只要我们传入需要排序的旗子列表和最终排布的顺序,我们就能得到给旗子排序的最少交换步骤。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3