• 蓝桥杯练习题二 - 合并检测(c++)


    题目如下

    新冠疫情由新冠病毒引起,最近在 A 国蔓延,为了尽快控制疫情,A 国准 备给大量民众进病毒核酸检测

    然而,用于检测的试剂盒紧缺。为了解决这一困难,科学家想了一个办法:合并检测。即将从多个人(k 个)采集的标本放到同一个试剂盒中进行检测。如果结果为阴性,则说明这 k 个人都是阴性,用一个试剂盒完成了 k 个人的检测。如果结果为阳性,则说明 至少有一个人为阳性,需要将这 k 个人的样本全部重新独立检测(从理论上看, 如果检测前 k−1 个人都是阴性可以推断出第 k 个人是阳性,但是在实际操作中 不会利用此推断,而是将 k 个人独立检测),加上最开始的合并检测,一共使用 了 k + 1 个试剂盒完成了 k 个人的检测。

    A 国估计被测的民众的感染率大概是 1%,呈均匀分布。请问 k 取多少能最节省试
    剂盒?

    以下程序实现了这一功能,请你补全以下空白处内容:

    1. #include
    2. int main()
    3. {
    4.     double m = 4537;
    5.     double min = 9999999;
    6.     double k, sum, ans;
    7.     for (k = 1; k <= 100; k++)
    8.     {
    9.         sum = (m - k) / k + 0.01 * m * k + 1;
    10.         __________________;
    11.     }
    12.     printf("%d\n", (int)ans);
    13.     return 0;
    14. }

    提示:
    设检测人数为100人,根据概率为1%,则只有1个为阳性。k个人一组,则需要的试剂数量
    为:对所有分组进行合并检测所需要的试剂数100/k+其中1个分组阳性所需要的试剂数k+
    未分组人数所需的试剂数量。 

    其实题中已经给出了部分代码,不过博主个人认为这个解题思路有点理解不了,很难让人明白为什么要这么做,有兴趣的同学可以顺着这个思路想下去,欢迎评论区讨论。

    今天博主的思考方式略微有些不同,咱们先看看代码,然后根据代码,一步步给大家解析思路,最终达到理解的程度:

    1. #include
    2. using namespace std;
    3. int main()
    4.   /*
    5.       检测总人数,我们假定一个值,也可以设置的更大,但其实没这个必要,想改值的也
    6.       可以试试,结果不出意外应该都一样
    7.   */
    8.   double m = 4537;
    9.   /*
    10.       每组人数最小值,这里设置一个绝对大的值,但肯定用不上,一组绝对不会这么多人,
    11.       作用是方便我们做比较的时候设置最小值
    12.   */
    13.   double min = 99999
    14.   /*
    15.       这里的三个值是我们需要用到来计算的,不得不叹息一声,数学才是万能的啊
    16.       k:每次合并检测的人数
    17.       sum:所需试剂盒数
    18.       ans:最优k的解
    19.   */
    20.   double k, sum, ans; 
    21.   /*
    22.     循环,直至找到最优解,k设置100是因为一组绝对不会100人,代价太大,我们
    23.     现实中检测也不过就是10人一组,因为一旦有一个人感染,那么必须一个人一个
    24.     试剂盒,绝对的浪费
    25.   */ 
    26.   for (k = 1;k < 100;k++)
    27.   {
    28.         /*
    29.             这里是总人数整除每组人数取余,如果刚好除尽,这么多人首次检测就只需
    30.             要m/k个试剂盒
    31.         */
    32.       if ((int)m % (int)k == 0)
    33.       {
    34.             /*
    35.                 m/k是首次检测这么多人需要的试剂盒,0.01*m是出现感染人的数量,
    36.                 因为感染人是平均分布的,所以可以认为有0.01*m的分组中,每组存
    37.                 在一个感染者,需要对这些组的每一个人进行单独的检测,每组人数为k,
    38.                 则二次检测需要0.01*m*k个检测盒,加起来就是一共的检测数
    39.             */
    40.           sum = m / k + 0.01 * m * k;
    41.       }
    42.       else
    43.       {
    44.           /*
    45.               这里和上面是一样的道理,因为除不尽,所以需要额外增加一个检测盒,
    46.               不过这里有个特殊情况,如果被感染者刚好存在于最后这个不足k人的
    47.               分组中,这一组总检测试剂盒数是不足k的,但是这种情况被忽略了,
    48.               原因是,即使不足k人,差距也不过就是几个,跟全体比起来微不足道,
    49.               这样的分组一般也存在极少数,所以这种极低概率事件在这种大数量检
    50.               测情况下可以忽略不计。(同学们切不可钻牛角尖,“大局为重”)
    51.           */
    52.           sum = m / k + 0.01 * m * k + 1;
    53.       }
    54.       //看这里,min派上用场了
    55.       if (sum < min)
    56.       {
    57.           //min=sum,所以每一次都取到的是sum(总试剂盒)的最小值
    58.           min = sum;
    59.           //最小值对应的k就是最佳每组人数
    60.           ans = k;
    61.       }
    62.   }
    63.   /*
    64.       最后输出最佳人数,为10,果然和我们现实中检测是一样的,厉害了,再次感叹,
    65.       算法来源于数学,数学牛逼
    66.   */
    67.   cout << ans << endl;
    68.   return 0;
    69. }

    注释写的非常清楚了同学们,仔细看就一定能理解这个算法,个人认为要比原题目中那种思路要容易理解的多。

     最后,有什么不理解的欢迎评论区留言讨论!
     

  • 相关阅读:
    金仓数据库KingbaseES客户端应用参考手册--20. wrap
    封装简易axios函数 获取数据 GET
    ASP.NET Core 3 高级编程(第8版) 学习笔记 04
    java计算机毕业设计springboot+vue网上购物商城系统
    714. 买卖股票的最佳时机含手续费
    JavaScript
    EPLAN学习笔记1:连接定义点和电位定义点
    YOLO系列之yolov1解读(1)
    【Midjourney入门教程4】与AI对话,写好prompt的必会方法
    C# WebService 发布到本地IIS----局域网访问/外网访问
  • 原文地址:https://blog.csdn.net/CodingFire/article/details/126489570