1  逻辑判断

对于逻辑判断问题,一般都要考虑全部的可能性,然后从这些可能性中按条件逐一排查,直到最后获得某个结论。

【百钱买百鸡问题】

问题描述:

雄鸡(cock)7元一只,母鸡(hen)5元一只,小鸡(chick)1元3只。花费100元,买100只鸡,如果雄鸡、母鸡、小鸡都必须有,则雄鸡、母鸡、小鸡各应买几只?

分析:

考虑全部的可能性时,先考虑雄鸡的最高耗费金额为100-5-1=94元,取7的倍数,得91元,所以雄鸡数量范围为1~13;同理可得,母鸡数量范围为1~18;小鸡数量范围为3~96(注意小鸡虽可以花费100-7-5=88元钱买来264只,但由于总鸡数量的限制,三种鸡都要有,则小鸡数应小于等于98,取3 的倍数,则为96)。

其程序表达式为:

  1. for(列举所有情况){ //可能为多重循环
  2. if(条件1不满足) continue;
  3. if(条件2不满足) continue;
  4. //...
  5. if(条件n不满足) continue;
  6. 输出结果之一或者累计符合所有条件的方案
  7. }

本题的条件为:

(1)雄鸡数量+母鸡数量+小鸡数量-100=0

(2)雄鸡花费+母鸡花费+小鸡花费-100=0

(3)小鸡数为3的倍数

因此其反条件为:

(1)cock+hen+chick-100!=0

(2)7*cock+5*hen+chick/3-100!=0

(3)chick%3!=0

注:只要条件值非零,即为真。因此条件“x!=0”等价于“x”,最初分析的程序应为:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. for (int cock = ; cock <= ;++cock)
  6. for (int hen = ; hen <= ;++hen)
  7. for (int chick = ; chick <= ; ++chick)
  8. {
  9. if ( * cock + * hen + chick / - ) continue;
  10. if (cock + hen + chick - ) continue;
  11. if (chick % ) continue;
  12. cout << "Cock: " << cock << ", Hen: " << hen << ", Chick: " << - cock - hen << endl;
  13. }
  14. cin.get();
  15. return ;
  16. }

运行结果:

还可以考虑程序的优化:由于chick=100-cock-hen,因此,确定了cock和hen也就确定了chick,可以省略chick这重循环。将所有有chick的地方用100-cock-hen代替。得到:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. for (int cock = ; cock <= ;++cock)
  6. for (int hen = ; hen <= ;++hen)
  7. //for (int chick = 3; chick <= 96; ++chick)
  8. {
  9. if ( * cock + * hen + (-cock-hen) / - ) continue;
  10. //if (cock + hen + chick - 100) continue;
  11. if (( - cock - hen) % ) continue;
  12. cout << "Cock: " << cock << ", Hen: " << hen << ", Chick: " << - cock - hen << endl;
  13. }
  14. cin.get();
  15. return ;
  16. }

也可按照下面的模式:

  1. for(列举所有的可能情况
  2. {
  3. if(条件1满足&&条件2满足&&...&&条件n满足)
  4. 输出结果之一或者累计符合所有条件的方案
  5. }

则得程序如下:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. for (int cock = ; cock <= ;++cock)
  6. for (int hen = ; hen <= ;++hen)
  7. //for (int chick = 3; chick <= 96; ++chick)
  8. {
  9. //if (7 * cock + 5 * hen + (100-cock-hen) / 3 - 100) continue;
  10. //if (cock + hen + chick - 100) continue;
  11. //if ((100 - cock - hen) % 3) continue;
  12. if (( - cock - hen) % == && * cock + * hen + ( - cock - hen) / == )
  13. cout << "Cock: " << cock << ", Hen: " << hen << ", Chick: " << - cock - hen << endl;
  14. }
  15. cin.get();
  16. return ;
  17. }

或者为:

  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. for (int cock = ; cock <= ;++cock)
  6. for (int hen = ,chick=-cock; hen <= ;++hen,chick--)
  7. //for (int chick = 3; chick <= 96; ++chick)
  8. {
  9. //if (7 * cock + 5 * hen + (100-cock-hen) / 3 - 100) continue;
  10. //if (cock + hen + chick - 100) continue;
  11. //if ((100 - cock - hen) % 3) continue;
  12. if (( - cock - hen) % == && * cock + * hen + ( - cock - hen) / == )
  13. cout << "Cock: " << cock << ", Hen: " << hen << ", Chick: " << - cock - hen << endl;
  14. }
  15. cin.get();
  16. return ;
  17. }

运行结果很显然和初始代码一样

2 级数逼近

循环的设计,对于无穷数列求和,逼近到某个近似值的情况。例如,数学公式:

π/4=1-1/3+1/5-1/7+...

求π的近似值,精确到小数点后6位。

分析:

(1)整数不能表示小数,所以π的值用浮点double表示。

(2)按公式,先求π/4。

(3)数列的第n项是(-1)n-1/(2n-1)。

(4)一种方法是根据循环变量n,求得第n项的值,累计,然后条件判断,若满足结束条件,则退出。循环条件为:前一个累计和与后一个累计和的差小于106。由于前后累计的结果之差的绝对值等于后一次加上去的值,所以,也可以通过判断后一项的绝对值小于106而得到循环退出条件。

  1. #include<iostream>
  2. #include<cmath>
  3. #include<iomanip>
  4. using namespace std;
  5. int main()
  6. {
  7. double sum = , item = ;
  8. for (int n = ; abs(item) > 1e-; ++n)
  9. {
  10. item *= (-1.0)*( * n - ) / ( * n - );
  11. sum += item;
  12. }
  13. cout << "Pi= " << setiosflags(ios::fixed) << setprecision() << sum * << endl;
  14. cin.get();
  15. return ;
  16. }

运行结果:

补充知识点:

【C++中setiosflags( )的用法】

setiosflags 是包含在命名空间iomanip 中的C++ 操作符,该操作符的作用是:执行由有参数指定区域内的动作;
iso::fixed 是操作符setiosflags 的参数之一,该参数指定的动作是以带小数点的形式表示浮点数,并且在允许的精度范围内尽可能的把数字移向小数点右侧;
iso::right 也是setiosflags 的参数,该参数的指定作用是在指定区域内右对齐输出;
setprecision 也是包含在命名空间iomanip 中的C++ 操作符,该操作符的作用是设定浮点数;

setprecision(2) 的意思就是小数点输出的精度,即:小数点右面的数字个数为2。

  1. cout<<setiosflags(ios::fixed)<<setiosflags(ios::right)<<setprecision();

合在一起的意思就是,输出一个右对齐的小数点后两位的浮点数。

使用setprecision(n)可控制输出流显示浮点数的数字个数。C++默认的流输出数值有效位是6。

如果setprecision(n)与setiosflags(ios::fixed)合用,可以控制小数点右边的数字个数。

(5)另一种方法是先设定一个初项,然后一边累计,一边根据前一项求下一项,一直累计,直到满足条件为止。

  1. #include<iostream>
  2. #include<cmath>
  3. using namespace std;
  4. int main()
  5. {
  6. double sum = , item = ;
  7. for (int denom = ,sign=; abs(item) > 1e-; denom+=,sign*=-)
  8. {
  9. item *= sign / double(denom);
  10. sum += item;
  11. }
  12. cout << "Pi= " << fixed<< sum * << endl;
    //此处的“fixed”表示用一般的方式输出浮点数,而不是科学计数法。
  1. cin.get();
  2. return ;
  3. }

流输出的默认精度是6位,与这里的输出要求一致,所以可以省略精度设置。由于直接用了fixed流状态操作,便可以省略流的辅助头文件iomanip。

denom存放每一项的分母值,它与sign都仅在for循环中使用,所以放在for循环初始处定义是清晰的。

abs是求浮点数的绝对值。调用abs函数,对于整数,其返回值也为整数;对于浮点数,其返回值也为浮点数。C++采用了一种函数重载的技术来实现这一编程的方便性。

当然,也可以用while循环来实现:

  1. #include<iostream>
  2. #include<cmath>
  3. using namespace std;
  4. int main()
  5. {
  6. double sum = , item = ;
  7. int denom = , sign = ;
  8. while (abs(item) > 1e-)
  9. {
  10. denom += ;
  11. sign *= -;
  12. item = sign*1.0 / denom;
  13. sum += item;
  14. }
  15. cout << "Pi= " << fixed << sum * << endl;
  16. cin.get();
  17. return ;
  18. }

运行结果:

for和while循环没有性能上的差异,两者在使用上完全反映了编程风格。作者更喜欢用for循环,一是因为希望履行局部变量尽量不要公开化的模块原则:denom、sign是局限于循环内的,能够让它们在循环描述中定义和初始化是最合适的;二是循环变量的修正,或者一切调整循环状态的语句,放在循环描述中也更显得直观,而且也压缩了循环体的规模,减轻了阅读强度。因此for循环体现了更好的结构性和简洁性。

在后面的章节中,作者刻意地在使用for而很少使用while,目的是在告诉读者,很多过程优化是从for循环下手的,调配for循环描述的三个部分构成了编程的初级艺术,它的根本性体现在对循环结构的深刻认识上。

那么能否用do-while语句来实现呢?能。只不过初值要改一下:

  1. #include<iostream>
  2. #include<cmath>
  3. using namespace std;
  4. int main()
  5. {
  6. double sum = , item = ;
  7. long denom = -;
  8. int sign = -;
  9. do
  10. {
  11. denom += ;
  12. sign *= -;
  13. item = sign*1.0 / denom;
  14. sum += item;
  15. } while (abs(item)>1e-);
  16. cout << "Pi= " << fixed << sum * << endl;
  17. cin.get();
  18. return ;
  19. }

运行结果:

看上去与while循环结构差不多,但其循环控制思路上差了一个节拍。作者并不主张这类问题用do-while解决,只有在迫不得已,即用while写出的循环很难看懂时,才偶尔用一下do-while。

C++ code:More Loop Designs的更多相关文章

  1. C++ code:for loop designs

    1  用for循环编出系列图形 该图形一共10行,每一行增加一个字符,所以应循环10次,每次输出一行.其循环模式为: :i<=;++i) { 输出第i行 换行 } 我们注意到,每一行长度的变化正 ...

  2. VS Code:让你工作效率翻倍的23个插件和23个编辑技巧

    VS Code:让你工作效率翻倍的23个插件和23个编辑技巧 总结了一些平时常用且好用的 VS Code 的插件和编辑技巧分享出来. 文章详情可查阅我的博客:lishaoy.net ,欢迎大家访问. ...

  3. Windows could not set the offline local information.Error code:0X80000001解决方法

    我的笔记本是联想Y460(白色) 昨天在重装系统的时候遇到如下错误:Windows could not set the offline local information.Error code:0X8 ...

  4. Code:Blocks 中文乱码问题原因分析和解决方法

    下面说说修改的地方. 1.修改源文件保存编码在:settings->Editor->gernal settings 看到右边的Encoding group Box了吗?如下图所示: Use ...

  5. Libevent:4event loop

    一:运行loop       一旦一些events在event_base注册之后(下一节会讨论如何创建和注册events),就可以使Libevent等待events,并且在events准备好时能够通知 ...

  6. HTML Standard系列:Event loop、requestIdleCallback 和 requestAnimationFrame

    HTML Standard系列:Event loop.requestIdleCallback 和 requestAnimationFrame - 掘金 https://juejin.im/post/5 ...

  7. JavaScript 运行机制详解:Event Loop

    参考地址:http://www.ruanyifeng.com/blog/2014/10/event-loop.html 一.为什么JavaScript是单线程? JavaScript语言的一大特点就是 ...

  8. JavaScript:event loop详解

    之前已经有两篇随笔提到了event loop,一篇是事件机制,一篇是tasks和microtasks,但是里面的event loop都是文字描述,很难说细,逻辑也只是简单的提了一遍.其实之前也是通过阮 ...

  9. VS Code:快捷方式

    转于:vscode: Visual Studio Code 常用快捷键 博主:魚魚 更多操作参见官网:https://code.visualstudio.com/docs/getstarted/key ...

随机推荐

  1. HSRP vs VRRP

    HSRP:(Hot Standby Router Protocol)-热备份路由协议 是cisco平台一种特有的技术,是cisco的私有协议. VRRP:(Virtual Router Redunda ...

  2. 将本地的代码推送到公网的github账号去

    将本地的代码推送到公网的github账号去 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 最近工作上需要用到github账号,拜读了一位叫廖雪峰的大神的文档,把git的前世今生说的 ...

  3. Calendar 日历类的时间操作

    我们经常会涉及到对时间的处理,例如登陆网站,我们会看到网站首页显示XXX,欢迎您!今天是XXXX年....某些网站会记录下用户登陆的时间,比如银行的一些网站,对于这些经常需要处理的问题,Java中提供 ...

  4. synchronized实现原理

    线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据.因此为了解决这个问题,我们可能需要这样一个方案, ...

  5. 在windows中停止mysql提示:'服务正在启动或停止中,请稍候片刻后再试一次'

    发现mysql的windows服务异常,准备卸载并重新注册服务,输入: mysqld --remove MySQL 提示: 发现卸载不掉这个服务,于是找到MySQL服务的pid sc queryex ...

  6. HDU1098---数学

    Ignatius's puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  7. 个股和股票池的beta系数的估算

    个股的beta系数的估算 代码 def test_gg_beta(symbol='000895.sz', start='2018-01-01', plot_price=True, align_to=' ...

  8. JAVA NIO 中的 zerocopy 技术提高IO性能

    关于一篇更详细更好的介绍 ZeroCopy技术的文章,可参考:JAVA IO 以及 NIO 理解 这篇文章介绍了 zerocopy技术来提高Linux平台上的IO密集型的JAVA应用程序的性能. ze ...

  9. 配置Arcengine10.1+java开发环境(Eclipse)

    以下开发环境配置是假定用户已经安装了Java开发的IDE(Eclipse) 软件准备 (一)ArcEngine 10.1 安装包 提取码:poa0 (二)ArcGIS License Manager ...

  10. oracle数据库还原以及备份 包括快速备份(并发压缩)

    expdp jhpt/XXXX directory=databackup dumpfile=dpfile_201512091300_%U.dmp filesize=5G parallel=8 comp ...