《编程之美》读书笔记连载(2)

題解/算法 {2612. 最少翻转操作数} 1 阅读详情

n 个烙饼经过翻转后的状态可组成一棵树。寻找翻转最少次数,相当于在树中搜索层次最低的某个节点。

由于每层的节点数,成几何数量级增长,在n 较大时,使用广度优先遍历树,会无法有足够的内存来保存中间结果(考虑到每层的两个节点,可以通过旋转,移位等操作互相转换,也许每层的状态或许可以用一个函数来生成,这样的话也就可以采用广度优先方法。)。因而采用深度优先。但这棵树是无限深的,因而必须找到最少翻转次数的上限值 ,当深度达到该值时不再继续往下搜索。最少翻转次数,必然大等于任何一种翻转方案所需的翻转次数,因而只要构造出一种方案,取其翻转次数即可。最简单的方案就是:对最大的未就位的烙饼,将其翻转,再找到最终结果中其所在的位置,翻转一次使其就位。因此,对编号在n-1 和2 之间的烙饼,共翻转了2*(n-2) 次,剩下0 和1 号烙饼最多只要翻转1 次,因而最少翻转次数的上限值是:2*(n-2)+1=2*n-3 (最新进展:上限值为18/11*n ),当然,最好还是直接计算出采用这种方法的翻转次数做为初值 。

 减少遍历次数:

1 避免出现已处理过的状态一定会减少遍历吗?答案是否定的, 深度优先遍历,必须遍历完一个子树,才能遍历下一个子树,如果一个解在某层比较靠后位置,若不允许处理已出现过的状态时,可能要经过很多次遍历才能找到这个解,但允许处理已出现过的状态时,可能会很快找到这个解,并减小“最少翻转次数的上限值”,使更多的分支能被剪掉,从而减少遍历。比如,说两个子树A 、B ,搜索子树A ,100 次后可得到一个解对应翻转次数20 ,搜索子树B ,20 次后可得到翻转次数为10 的解,不允许处理已出现过的状态,就会花100 次遍历完子树A 后,才开始遍历B ,但允许翻转回上一次状态,搜索会在A 、B 间交叉进行,就可能只要70 次找到子树B 的那个解(翻转次数为10+2=12 ),此时,翻转次数比较少,能减小更多的搜索,搜索次数明显减少。以书中的{3,2,1,6,5,4,9,8,7,0} 为例,按后面的程序,需要搜索195 次,若可以走回头路,只要搜索116 次。

 2 如果最后的几个烙饼已经就位,只须考虑前面的几个烙饼。 对状态(0,1,3,4,2,5,6) ,编号为5 和6 的烙饼已经就位,只须考虑前5 个烙饼,即状态(0,1,3,4,2) 。如果一个最优解,从某次翻转开始将移动了一个已经就位的烙饼,那么,这个解法,从这次翻转开始得到的一系列状态,从中将这个烙饼,得到新的状态,可以设计出一个新的解法对应这系列新的状态。该解法所用的翻转次数不会比原来的多。

 3 估计每个状态还需要翻转的最少次数(即下限值),加上当前的深度,如果大等于上限值,就无需继续遍历。这个下限值可以这样确定:从最后一个位置开始,往前找到第一个与最终结果位置不同的烙饼编号(也就是说排除最后几个已经就位的烙饼),从该位置到第一个位置,计算相邻的烙饼的编号不连续的次数,再加上1 。 每次翻转最多只能使不连续的次数减少1 ,但不少人会忽略掉这个情况:最大的烙饼没有就位时,必然需要一次翻转使其就位,而这次翻转却不改变不连续次数。(可以在最后面增加一个更大的烙饼,使这次翻转可以改变不连续数。) 如:对状态(0,1,3,4,2,5,6) 等同于状态(0,1,3,4,2) ,由于1 、3 和4 、2 不连续,因而下限值为2+1=3 。下限值也可以这样确定:在最后面增加一个已经已就位的最大的烙饼,然后再计算不连续数。 如:(0,1,3,4,2) ,可以看作(0,1,3,4,2,5) ,1 和3 、4 和2 、2 和5 这三个不连续,下限值为3 。

 4 翻转次数的上限值越大,搜索次数就越多,尽快找到一个接近最优解的解,能减少大量的搜索次数。可以采用贪心算法,通过调整每次所有可能翻转的优先搜索顺序 ,来找到这样的解。比如,优先搜索使“下限值”减少的翻转,其次是使“下限值”不变的翻转,最后才搜索使“下限值”增加的翻转。对“下限值”不变的翻转,还可以根据其下次的翻转对“下限值”的影响,再重新排序。由于进行了优先排序,翻转回上一次状态能减少搜索次数的可能性进一步的降低。

 5 剪枝:第m 次翻转时,“上限值”为min_swap 。

(1.3_pancake_final.cpp 用到的剪枝条件)

如果在某个位置的翻转得到一个解(即翻转次数为m ),则其它位置可以不搜索(因为在其它位置的翻转,能得到的最少翻转次数必然大等m )。

如果在某个位置的翻转后,“下限值”为k ,并且 k+m>=min_swap ,则对所有的使新“下限值”kk 大等于k 的翻转,都有 kk+m>=min_swap ,因而都可以不搜索。

      另外,由于翻转时,只有两个位置的改变才对“下限值”有影响,因而可以记录每个状态的“下限值”,翻转时,通过几次比较,就可以确定新的“下限值”,没必要从新开始计算新状态的“下限值”。

 针对书上的例子,最终的代码,只调用了搜索函数29 次,翻转函数66 次(这个例子比较特殊,min_swap 直接指定2*10-2=18 时,调用搜索函数29 次,翻转函数56 次)。

 另外,判断不连续次数时,最好写成 -1<=x && x<=1 ,而不是x==1 || x==-1 。对于 int x; a<=x && x<=b ,编译器可以将其优化为 unsigned (x-a) <= b-a 。我最初写的代码用的类型都是size_t ,就手动优化了。后面给出两个文件(1.3_pancake.cpp 和1.3_pancake_final.cpp )完整代码。可以用前一个测试“是否允许翻转回上次状态”对搜索次数的影响。

 (补充:

在网上下了“第 6 刷”的源代码,结果编译时仍是一堆错误,主要错误有:

1 Assert 应该是 assert

2 m_arrSwap 未被定义,应该改为 m_SwapArray

3 Init 函数两个 for 循环,后一个没定义变量 i ,应该将 i 改为 int i

另外,每运行一次 Run 函数,就会调用 Init 函数,就会申请新的内存,但却没有释放原来的内存,造成内存泄漏。

 程序的低效主要是由于 进行剪枝判断时,没有考虑好边界条件。

1  if(step + nEstimate > m_nMaxSwap)  这个最好取大等于号。

2  判断下界时,如果最大的烙饼不在最后一个位置,则要多翻转一次,因而在 LowerBound 函数 return ret; 前插入一行 if (pCakeArray[nCakeCnt-1]!=nCakeCnt-1) ret++; 。

  3  n 个烙饼,翻转最大的 n-2 烙饼最多需要 2*(n-2) 次,剩下的 2 个最多 1 次,因而上限值为 2*n-3 ,因此, m_nMaxSwap 初值可以设为 2*n-3+1=2*n-2 ,这样每步与 m_nMaxSwap 的判断就可以取大等于号。

 1 和 2 两处任改一处都能使搜索次数从 172126 降到两万多,两处都改,搜索次数降到 3475 ,再改动第 3 处,搜索次数最终为 2989 。

 P24 页,“目前找到的最大下界是 15n/14 ”,这句有问题,没说清楚这个“下界”是指什么,会认人误以为,任意一个排列的最少翻转次数。这应该是后面提到的“第 n 个烙饼数”的下界。

 PS ,找这个代码时,无意间看到 1-17 的代码居然有 void main() 这种错误写法。)

原文链接:http://blog.youkuaiyun.com/flyinghearts/archive/2010/05/18/5605918.aspx

延伸阅读:

2517 最少01翻转次数(前后缀和经典例题) 题目描述: 小b有一个01序列,她每次可以翻转一个元素,即将该元素从0变1或者从1变0。现在她希望序列不降,求最少翻转次数。 输入 第一行输入一个数n,其中1≤n≤20000; 第二行输入一个由‘0’和‘1’组成的字符串 输出 输出一个非负整数,表示翻转次数 输入样例 6 010110 输出样例 2 解题思路分析: 首先,他是一个01序列对吧 输入是这样的,没有空格隔开 所以我们只能用作字符串输... 阅读详情

相关推荐

《编程之美》——读书笔记

最近花了几天时间把《编程之美》这本书好好读了一遍,感觉收获还是挺大的。 于是决定做个笔记,算是简单的摘录一些书中的精彩思想,也算重新回顾思考下   1.5 快速找出机器故障 问题描述: 有很多的ID(可能位数很大),其中只有一个ID出现的次数小于2,其他正常ID出现的次数都等于2,求这个次数为1的ID 精彩解法: 将所有的数从头到尾异或一遍,这样得出来的最终结果就是所求的答案。 拓

勿忘初衷 4225

位运算 ----力扣2220

位运算

m0_72410274的博客 652

《编程之美》读书笔记1——求二进制数中1的个数

前言:又到了一周一次的写博客环节了,嗯···没什么存货了,上一周没有看多少关于数据结构的内容,也没记什么笔记;我挣扎了一下,想停更一周,但是好不容易坚持了9周,一定要坚持到今年考研结束,甚至坚持到以后。我决定借鉴一下上次凑单买的《编程之美》的一个关于位运算的案列,“水”一期博客。 一、问题提出 对于一个字节(8bit)的无符号整型变量,求其二进制表示中"1"的个数 相关概念补充:1字节包含8位,...

Star_jiang的博客 394

NYOJ1059最小翻转次数

最小翻转次数 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 给你一串长度为18的01序列,它们的编号从左到右依次为1,2,3......16,17,18。 定义每一次参数为k(1 给定一个初始状态和一个目标状态,问你最少需要几次翻转(每次翻转的k值可以任意选取)可以从起始状态达到目标状态。  输入首先输入T,表示有T组测试用例。注意T会很大(10

z956281507的博客 2057

编程之美 - 读书笔记 - 卖书折扣问题的贪心解法

《编程之美》读书笔记(四):卖书折扣问题的贪心解法       每 次看完《编程之美》中的问题,想要亲自演算一下或深入思考的时候,都觉得时间过得很快,动辄一两个小时,如果再把代码敲一遍的话,需要的时间可能更长,真 是搞不懂通过微软面试的那些家伙的脑袋到底什么构造,书的序言中提到他们每次面试45分钟,还要写出程序?!在我看来,如果是控制CPU曲线或是中国象棋 问题或许还有可能,如果是买书折扣问题

phphot 2407

最小翻转次数

Problem statement: 问题陈述: Given a binary string (containing only 0s and 1s). We need to make this string a sequence of alternate characters (0 and 1) by flipping some of the bits, our goal is to mini...

cumtb2009的博客 1429

FPGA之全数字锁相环(DPLL)

1. 数字锁相环的基本原理和组成 1.1 锁相环(PLL)的简介 锁相环最开始并不是用在数字电路中,而是模拟短路中。对于模拟电路中的锁相环,大家可以参考这篇文章稍微看一下,数字和模拟只是实现的方法不同,但是原理、步骤还是共同的。关于模拟PLL。可以参考一片文章: http://www.sohu.com/a/190569594_464086 首先在学习数字锁相环之前,我们应该先了解什么是锁相环?锁相...

DBLLLLLLLL的博客 5万+

编程之美读书笔记——目录

      最初看《编程之美》时,总觉得有些解法与自己的最初想法差得太多,于是就有了将自己的想法记下来的冲动。三个月下来,也才弄了十几篇,这些笔记都发给了该书的编辑。静下心来,翻翻自己所做的笔记,总觉得写得很杂乱,有不少错处,现将这些笔记贴出来,希望能得到大家的指正。   目录: 编程之美读书笔记_1.2_中国象棋将帅问题 编程之美读书笔记_1.3 一摞烙饼的排序 编程

flyinghearts的专栏 3341

Nest的限流方案

多维度限流(如 IP、用户 ID、接口级别、请求类型)可配置化(支持不同环境和接口动态配置)可观测性(接入日志、监控系统)高性能和分布式支持(Redis 限流器)与鉴权鉴权链路集成(结合 JWT、API Token)以下是一个“标准// 优先按用户ID限流,否则按IP在main.ts维度建议限流存储推荐 Redis 支持多实例限流 Key 设计支持 IP + 用户ID + 路由等多种维度限流策略精细化配置,接口粒度调整异常处理自定义响应体、日志告警观测性。

Bruce__taotao的博客 1196

逆向实战:喜马拉雅新版xm-sign算法解析与本地化生成方案

本文深入解析了喜马拉雅新版xm-sign算法的逆向过程与本地化生成方案。通过详细拆解browserid和sessionid的生成机制,提供了基于Node.js的核心代码实现,帮助开发者在不依赖官方环境的情况下生成有效签名。文章还涵盖了参数获取技巧、常见问题排查及性能优化建议,为爬虫开发者提供了实用的技术参考。

weixin_29256771的博客 299

[读书笔记]编程之美(一)

[读书笔记]编程之美(一)不得不说编程之美是一本很有意思的书,里面的各式各样新奇的问题,总是可以通过课上讲的简单的问题来解决,对于训练自己的思维的确有很大的好处。一般解决复杂的问题,我们总是可以通过:1、画图:链表、二叉树,2、举例,3、分解:分治法、动态规划来解决。游戏 程序也是游戏的一种1.1让CPU占用率曲线听你指挥 题目:用户决定CPU的占有率 思路:(举例)首先我们要明确什么是CPU的占有

xy_cpp的博客 1万+

Winform从入门到精通(1)——Label(史上最全)

本篇文章是对专栏《winform控件从入门到精通》的详细介绍

qq_34059233的博客 4万+

《编程之美》读书笔记

《编程之美》读书笔记(一):中国象棋将帅问题  (http://www.cnblogs.com/bvbook/archive/2008/07/24/1250507.html)  《编程之美》读书笔记(二):“求二进制数中1的个数”扩展问题  (http://www.cnblogs.com/bvbook/archive/2008/07/24/1250535.html)  《编程之美》读书笔记

llw01的专栏 998

2026华为OD面试题029:勇攀数字高峰

在给定的数字地形图里寻找登山路径,数字代表当前位置的海拔高度。要求从最低海拔出发,不断攀登,最终到达最高山峰。地图保证最低海拔和最高山峰都只有一个。 登山规则: - 路径上的海拔必须严格递增 - 只能向上下左右 4 个方向移动 - 路径必须从最低海拔开始,到最高海拔结束 - 每个地点只能走一次 - 每一步的攀登高度差必须大于 0,且不超过指定值 `K` 输出满足条件的登山路径的数量。

琅嬛福地 119

053、坏点校正(DPC)进阶:静态坏点标定与动态坏点检测算法对比

文章摘要: 本文深入探讨了图像传感器坏点校正(DPC)技术,重点对比静态坏点标定与动态坏点检测算法。作者结合真实案例,指出静态标定在高增益场景下的局限性,并详细解析动态检测的核心算法、参数调优及常见误检问题(如边缘/纹理干扰)。提出“静态为主+动态为辅”的混合方案,强调阈值需随增益、亮度和温度自适应调整。文末总结六条工程建议,包括避免固定阈值、优先使用中值替换、定期更新坏点表等,强调DPC是图像质量的基础防线,需结合传感器特性综合优化。

zzfmlxs的博客 263

编程之美读书笔记 汇总

(1)编程之美读书笔记(1)二进制数中1的个数 (2)编程之美读书笔记(2)大数问题(高精度运算) (3)编程之美读书笔记(3) 统计在从1到n的正整数中1出现的次数 (4)编程之美读书笔记(4)寻找最大的K个数 (5)编程之美读书笔记(5)最大公约数

落日小屋 1974

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

《编程之美》读书笔记集锦

《编程之美》读书笔记(一):中国象棋将帅问题 http://www.cnblogs.com/bvbook/archive/2008/07/24/1250507.html《编程之美》读书笔记(二):“求二进制数中1的个数”扩展问题 http://www.cnblogs.com/bvbook/archive/2008/07/24/1250535.html《编程之美》读书笔记(三): 一摞烙

linxhpku的专栏 692

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

[读书笔记]编程之美(二)

[读书笔记]编程之美(二)2.1求二进制数中1的个数 问题:对于一个字节(8bit)的无符号整形变量,求其二进制表示中“1”的个数,要求算法的执行效率尽可能高。 思路: n = n & (n-1);当然因为只有8bit所以直接定义一个256的int数组表,直接返回结果,时间复杂度是O(1)。2.2不要被阶乘吓到 问题:1.给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N!=362

xy_cpp的博客 569

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

读书笔记:《编程之美》

《编程之美》读书笔记 我所阅读的《编程之美》是由《编程之美》小组所编写,由电子工业出版社出版,出版时间为2018年11月。此书的由来是有关于微软的面试,后来被用来教授人们一些编程技巧。该书的作者们大多从游戏出发,提出问题,循循善诱,引导读者进行阅读,学习,编程。阅读的过程中不会感到枯燥,而会感到越发有趣,大部分的问题都会在最后配上可以实现的代码来帮助读者学习,简直就是从小白到大神的一条光明大道。 本书其中一个题目就是控制CPU的占用率,这本是来自微软面试的一个问题,作者们尽管自有办法,但仍想从面试者那里看看

Be_Flamingo的博客 1688

精选的一些《编程之美》相关资料

转载自:http://blog.youkuaiyun.com/wuyuegb2312/article/details/9896831 又要到一年的招聘季了,肯定又有很多人开始啃《编程之美》了吧。这本书从开阔视野的角度来说很好,不过限于篇幅,有的问题并没有讲清楚(甚至问题叙述模棱两可、被标榜为“鼓励同面试官交流以获得更多细节”);或者扩展问题本身很难,没有给予解答和提示。在我看书并在网络上查到的相关资

nanjunxiao的专栏 1349

编程之美读书笔记

《编程之美》读书笔记23: 1.1    让CPU占用率曲线听你指挥 《编程之美》读书笔记01: 1.2    中国象棋将帅问题  《编程之美》读书笔记02: 1.3    一摞烙饼的排序* 《编程之美》读书笔记03: 1.4    买书问题* 《编程之美》读书笔记04: 1.8    小飞的电梯调度算法 《编程之美》读书笔记05: 1.9    高效率的安排

in_han 的专栏 936
上一篇: (转)什么妨碍我们进步
下一篇: 华为面试题:环球航行,空中加油
BOPGroup
博客等级 码龄17年 2525粉丝 306原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值