黑白按键,本题是2021年8月14日举办的第13届蓝桥杯青少组Python编程选拔赛真题。题目要求编程计算按几次按键可以使初始图变为最终图,如果不能实现则输出0。
先来看看题目的要求吧。
编程实现:
有一组黑白按键,每按下其中一个按键,其相邻的按键和它本身都会变成相反的颜色(黑色变白色,白色变为黑色)。
如果按下的按键非最左边和最右边按键,则其本身和左右相邻的两个按键变相反颜色;
如果按下最左边按键,则其本身和右边相邻的一个按键变相反颜色;
如果按下最右的按键,则其本身和左边相邻的一个按键变相反颜色。
给出一张“初始图”和一张“最终图”。通过按下按键,使“初始图”变为“最终图”,求最少需要按几次可以完成。
如:初始图为黑、白、黑3个按键(状态表示:010),最终图为白、白、黑3个按键(状态表示:110)。
首先按下2号按键,3个按键颜色变为白、黑、白(状态标识:101),然后按下3号按键,3个按键颜色变为白、白、黑(状态标识:110),故使初始图”变为“最终图”最少需要按2次。
如下图:
输入描述:
第一行输入一个由“0"和“1"组成的字符串,字符串长度为n(1< n < 26),表示游戏初始图状态,“0"表示黑色按键,“1"表示白色按键
第二行输入一个由“0"和“1"组成的字符串,字符串长度为n(1 < n < 26),表示游戏最终图状态,“0"表示黑色按键,“1"表示白色按键
输出描述:
输出一个整数,如果通过按键不能使初始图变为最终图,则输出“0,否则输出最少需要按几次按键可以使初始图变为最终图
样例输入:
010
110
样例输出:
这是一道算法题,考查的算法有模拟和回溯,涉及的知识点包括循环、条件、列表和函数和排列组合等。
def flip(color, index):
pass
如果index = 0,翻转自己和右邻居的按键; 如果index = n - 1,翻转自己和左邻居的按键; 如果index不在两端,则翻转自己和左右邻居的按键;
使用permutations()函数 使用回溯算法
思路有了,接下来,我们就进入具体的编程实现环节。
定义翻转函数
定义回溯函数
计算最小次数
1. 定义翻转函数
根据前面的思路分析,定义翻转函数如下:
代码不过,说明4点:
1). 参数color表示当前按键的状态,类型是字符串,index表示当前按键的编号,从0开始;
2). 为方便处理,将color转成列表,翻转完成后,再转成字符串,作为函数的返回值;
3). 如果index > 0,说明有左边的按键,将左边按键翻转,如果index < len(color) -1,说明有右边的按键,将右边按键翻转,对于当前位置index来说,直接翻转;
4). 在翻转按键的时候,使用了if...else的条件赋值语句,代码更加简洁,如果不熟悉,也可以改成if...else条件语句;
2. 定义回溯函数
回溯函数的写法基本上是固定的,编写代码如下:
代码不多,但是理解起来还是有些难度的,说明3点:
1). 函数参数有两个,color表示当前按键状态,flips表示翻转次数,每调用一次backtrack()函数,flips就增加1次;
2). 代码中用到了两个全局变量,第一个是min_flips,它表示最小翻转次数,需要在函数中进行修改,因此要加上global关键字进行声明,final表示按键的最终状态;
3). 结束回溯有3种不同的情况,第一种是color = final,就是已经翻转到最终状态了,此时要更新min_flips,第二种是flips > min_flips,说明这不是我们要的结果,那就直接结束,这就是所谓的剪枝,第三种是全部回溯完毕,说明无解,直接返回,注意三者的顺序,不能随意更改;
3. 计算最小次数
最后就是主程序了,获取用户的输入并调用函数,代码如下:
代码比较简单,说明两点:
1). 变量min_flips表示最小翻转次数,初始化的时候要设置为最大值,这里的float('inf')表示无穷大;
2). 调用backtrack()函数之后,如果不能翻转成功,那么min_flips是没有更新的,其值仍然是float('inf'),此时直接输出0。
至此,整个程序就全部完成了,你可以输入各种不同的按键状态来测试效果啦。
循环语句;
条件语句,尤其是带条件单独赋值语句;
列表的使用;
列表和字符串的转换;
自定义函数;
模拟算法;
回溯算法;
本题代码不少,难度较大,这里的关键点是对两种算法的灵活运用,一是模拟算法,二是回溯算法。
所谓模拟算法,就是利⽤计算机对⼀个过程进⾏模拟,通过改变数学模型的各种参数,观察这些参数的变化所引起的过程状态的变化,并从中得出答案。
比如,使用计算机编程模拟抛硬币得到正反面概率的情况,模拟报数游戏等。
一般来说,不是用经典算法解出来的算法都可以称为模拟算法,本题的翻转按键也是一个典型的模拟算法。
而回溯算法,其本质仍然是枚举算法,但它做了一些改进和优化,它跟暴力搜索最大的不同在于,在回溯算法里,会对每一步探测到的情况进行评估,如果当前的情况已经无法满足要求,那么就没有必要继续进行下去,也就是说,它可以帮助我们避免走很多的弯路。
超平老师给你留一道思考题,如果不使用回溯算法,直接使用permutations()函数,如何获取最小翻转次数呢?
你还有什么好的想法和创意吗,也非常欢迎和超平老师分享探讨。
需要源码的,可以添加本人微信。
另外,超平老师创建了一个蓝桥杯备考交流群,这是专门为老师和家长打造的免费社群,您可以与来自全国各地的老师、家长共同交流经验,分享学习心得。
超平老师也会给大家带来及时的赛事动态,备考攻略,真题资源分享,帮助各位更好地备考第15届蓝桥杯赛事,力争取得优异的成绩。
扫码或长按加入微信群