【题目描述】:
给定一个成有一些黑色豆子和一些白色豆子的咖啡罐以及一大堆“额外”的黑色豆子。重复下述过程,直至罐中只剩一颗豆子为止:
(1)从罐子中每次随机选取两颗豆子;
(2)若颜色相同,就将它们都扔掉并放入一个额外的黑色豆子;
(3)若颜色不同,就将白色豆子放回罐子中,而将黑色的豆子扔掉。
请设计程序模拟该过程,证明该过程会终止,从得出的结果推断出最后剩下豆子的颜色与最初白色豆子和黑色豆子的数量有什么数学关系?

【分析】:
题目抽象,有两个要求,第一个是设计程序模拟题目描述的过程,第二个是分析程序结果与咖啡豆数量之间的关系。
题目并没有说明咖啡罐中有多少粒咖啡豆及咖啡颜色的比例,故这是程序执行中需要输入的变量。
题目存在如下规则:
1)若摸出的咖啡豆同色,则放入一个黑咖啡豆;
2)若摸出的咖啡豆异色,则放入一个白色的咖啡豆;
由此条件可联想到离散数学的异或操作(XOR):
相同的两个数,异或结果为 0;
相异的两个数,异或结果为 1 。
由于咖啡豆颜色相异时放回白咖啡豆,故可用 0 代表黑咖啡豆,用 1 代表白咖啡豆。为满足咖啡豆的放入和丢弃操作,可选用链表来执行添加和操作的数据结构来存储咖啡豆。
最后一个咖啡豆与初始咖啡豆数量之间的关系:
设咖啡罐中共有 N 粒咖啡豆,其中黑色咖啡豆有 b 粒,白豆咖啡豆有 w 粒。每次取豆后咖啡罐中的豆数量都会减一,即 N 减一。每次取出两颗豆子总量都会减少1,则最后罐子中只剩一个,该过程一定会终结。
每次取的咖啡豆颜色有如下 3 种情况:
@两粒咖啡豆都是黑色(bb),把 2 个都扔掉,再放回 1 个额外的黑色豆子,
故此时黑色咖啡豆表示为: b-2 +1=b-1;
@两粒咖啡豆都是白色(ww),把 2 个都扔掉,再放回 1 个额外的黑色豆子,
故此时白色咖啡豆表示为: w-2 ;
@两粒咖啡豆颜色不同(bw),丢黑留白,即黑色咖啡豆减 1,白色咖啡豆数量不变。

由此可知,白色咖啡豆的数量要么不变化,要么两个两个的减少。
由此得出,若一开始咖啡罐里白色咖啡豆的数目为偶数,则剩下的一粒咖啡豆必然是黑色;若白色咖啡豆的数量为奇数,则剩下的一粒咖啡豆必然是白色。
由此看出,该题是利用“随机取出”字眼设置了一个陷阱,最后结果是固定的,与随机取出无关,只与咖啡豆的初始数量的奇偶性有关。

编译环境:
使用DEV C++来编译时,程序正常,不报错,但使用Visual C++来编译时程序会报如下错误:

这只是对 i 变量的定义问题,代码如下的 i 定义在DEVC++是允许的,使用 i 时就在内部定义,此处的 i 是同一个变量;

但在Visual C++中不允许同一变量的重复定义,故应将第二个for()循环里的 i 变量的定义去掉:

其实最好的解决方法应该是将变量 i 的定义放在for() 循环外,统一定义,而不是多次定义==》

运行结果:

代码:

#include <iostream>
#include <vector>
#include <time.h>
#include <stdlib.h>
using namespace std;//定义咖啡罐类
class CoffeeJar{
public:CoffeeJar(int blackNum, int whiteNum){     //构造函数,初始化变量blackNumber = blackNum;whiteNumber = whiteNum;total = blackNumber+whiteNumber;int i;for (i = 0;i<blackNumber;i++){jar.push_back(0);}for (i = 0;i<whiteNumber;i++){jar.push_back(1);}}~CoffeeJar(){jar.clear();delete &jar;                   //析构函数,回收vector的空间}void getCoffeeBean();            //随机抽取豆子的方法bool isWhiteBean(int color){    //判断豆子的颜色是否为白咖啡豆return color == 1;}int getTotal(){            //获取咖啡豆的总数 return total;}void printBeanColor();         //打印咖啡豆颜色
private:vector<int> jar;               //存储咖啡豆,0表示黑色,1表示白色int blackNumber;               //黑色咖啡豆数目int whiteNumber;               //白色咖啡豆数目int total;                     //咖啡豆的总数目
};//随机抽取咖啡豆
void CoffeeJar::getCoffeeBean(){int fBean = 0;      //初始化取的第一个豆子的颜色int sBean = 0;     //初始化取的第二个豆子的颜色srand(static_cast<unsigned>(time(0)));           //设置随机数种子int maxRand = total;                             //设置随机数范围,即最大值int fIndex = rand()%maxRand;                     //随机抽取的第一粒豆子的下标 int sIndex = rand()%maxRand;                     //第二粒豆子的下标    if (fIndex != sIndex){                            //两次抽取的豆子不能使同一个  fBean = jar[fIndex];                         //设置第一粒咖啡豆的颜色sBean = jar[sIndex];                         //设置第二粒咖啡豆的颜色if(fBean == sBean){             //如果两粒咖啡豆的颜色相同  vector<int>::iterator iter = jar.begin()+fIndex;jar.erase(iter);                        //删除一粒咖啡豆if (jar.size() != 1) {            //如果第二粒咖啡豆的存储位置在第一粒之后,索引减少一个 if(sIndex!=0 && sIndex > fIndex) { sIndex--; } iter = jar.begin()+sIndex;         //移除咖啡豆 jar.erase(iter);jar.push_back(0);                   //添加一个黑色豆子 } else { jar[0] = 0;        //如果罐子中只剩一粒咖啡豆则直接添加黑色豆子 } }else{                    //如果两次取的豆子颜色不同则删除黑色豆子 if (!isWhiteBean(jar[fIndex])){     //判断豆子颜色vector<int>::iterator iter = jar.begin()+fIndex;jar.erase(iter);}else if (!isWhiteBean(jar[sIndex])){vector<int>::iterator iter = jar.begin()+sIndex;jar.erase(iter);}            }total = jar.size();             //更新咖啡罐中的咖啡豆总数}}//打印咖啡罐中的咖啡豆颜色
void CoffeeJar::printBeanColor(){for (vector<int>::iterator i=jar.begin();i!=jar.end();++i){cout<<(*i)<<endl;}
}//主函数
int main(){int blackBeans,whiteBeans;             //黑色咖啡豆和白色咖啡豆的数目cout<<"请输入黑色咖啡豆和白色咖啡豆的数目:"<<endl;cin>>blackBeans>>whiteBeans;CoffeeJar *j = new CoffeeJar(blackBeans,whiteBeans);       //初始化咖啡罐while (j->getTotal()>1){j->getCoffeeBean();}cout<<"最后剩余的咖啡豆颜色为:"<<endl;j->printBeanColor();                       //打印最终剩余的咖啡豆的颜色return 0;
}

C++面试进阶之咖啡罐问题相关推荐

  1. 多个切点 boot spring_全网独家Spring/Cloud/MVC/Boot,脑图+面试+进阶,就问你服不服?...

    近期搜刮了一些Spring全家桶系列的思维脑图.经典面试题和进阶学习的PDF笔记(非常nice),Spring+SpringCloud+SpringMVC+SpringBoot,一个都没落下全都有!一 ...

  2. 面试进阶之字符串常量池

    转载自  面试进阶之字符串常量池 作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么,我们带着以下三个问题,去理解字符串常量池 ...

  3. android 让dialog保持在最前_Android 面试进阶指南 —— 唠唠任务栈,返回栈和启动模式...

    Android 面试进阶指南目录 唠唠任务栈,返回栈和启动模式 唠唠 Activity 的生命周期 扒一扒 Context 为什么不能使用 Application Context 显示 Dialog? ...

  4. Android知识体系总结2020(全方面覆盖Android知识结构,面试进阶)

    Android知识体系总结(全方面覆盖Android知识结构,面试&进阶 Version-3.0.0 时间:2020.05) 此篇文章是初中高级工程师学习文章,知识体系较为完整.有如下特点: ...

  5. Java面试进阶:Dubbo、Zookeeper面试题锦集

    Dubbo面试题锦集 1.默认也推荐使用netty框架,还有mina. 2.默认是阻塞的,可以异步调用,没有返回值的可以这么做. 3.推荐使用zookeeper注册中心,还有redis等不推荐. 4. ...

  6. 55万字,阿里内部最新最全Java面试进阶手册,能横扫95%的面试官

    又到了金三银四,为了让大家能在面试中过关斩将,小编特地找了在阿里的朋友要了这份内部不外传秘籍:55万字Java面试手册. 这份面试手册涉及的技术栈非常全面而且足够细致,内容包括网络协议.Java基础. ...

  7. BAT面试进阶:最全Memcached面试30题含答案

    [memcached面试题目] Memcached服务在企业集群架构中应用场景? Memcached服务在不同企业业务应用场景中的工作流程? Memcached服务分布式集群如何实现? Memcach ...

  8. Java面试进阶指北

    不难发现,近几年的面试难度越来越大,想要找到一份还不错的工作越来越难.越来越多的人开始抱怨:"CS领域是真特么卷!".然而,单纯抱怨有用么?你对其他求职者说:"大家都不要 ...

  9. 面试进阶齐飞!Github一天万赞的阿里Java系统性能优化有多牛?

    前两天在知乎上看到一个问答,说的是: 一个Java程序员具备什么样的素质和能力才可以称得上高级工程师? 这个问题也引发了我的一些思考,可能很多人会说,"作为高级工程师,基础得过硬.得熟练掌握 ...

最新文章

  1. 使用 Angular 打造微前端架构的 ToB 企业级应用
  2. optee的启动过程
  3. 让改变输入法回车键的图标
  4. 编写自己的Matcher与如何让编译器识别被mock的重载函数
  5. 如何快速搭建一个免费的,无限流量的Blog
  6. 【留言板】可编辑输入框操作总结
  7. 位置服务器管理器,查看 DIMM 位置
  8. 图像控制点 形变_基于控制点的图象变形方法及其应用
  9. Twitter数据抓取的方法(三)
  10. 快速取得三位数的个位,十位,百位
  11. PBC密码学库使用指南
  12. 怎么让HTML的属性横着排,css标签怎么设置横向排列
  13. html5编写软件哪个好?八款html5编写软件推荐
  14. u盘如何在计算机应用内存,u盘扩大内存,小编教你如何用U盘扩展内存
  15. Altium Designer原理图标题栏显示参数的解决方法
  16. 数据仓库架构演进与菜鸟实时数据仓库设计
  17. realme真我gt能升级鸿蒙系统吗,realme真我GT Neo闪速版曝光,换用双电芯电池
  18. 二维码(生成以及扫一扫)
  19. 搜索技巧:最全面的检索知识讲座
  20. Webug靶场之旅——显错注入

热门文章

  1. GPS与LBS的差别
  2. linux bin目录下存放的什么,Linux_Linux根目录下主要目录功能说明,/bin:存放最常用命令;   /b - phpStudy...
  3. 如何将PlayStation 4恢复出厂设置
  4. 自己开发基于Web的打印控件,真正免费不是共享
  5. 《Android自定义控件》RulerView,仿唯品会身高、体重等标尺,尺码控件,滑动可修改刻度值
  6. 毫米、微米、英寸、目数对照表
  7. 译:在ROS上发布Odometry信息
  8. RGB彩色空间的不同转换公式 1
  9. 王者荣耀最低战力查询-王者战区修改
  10. matlab报错问题处理,函数或变量无法识别,不受支持的符号、不可见的字符或非 ASCII 字符的粘贴———卸载之前