C++积累01_几个人各隔一定时长放炮问题

前两天看到有很多帖子说写自己的博客是帮助自己技术积累沉淀的有效方法,我想了想确实觉得挺有道理。自己要学的东西挺多,大一刚开始学c++,有好多细的点需要多多记忆,有好多方法也要记住。写成的文件毕竟打开比较费时间,我就写在这里,尽量每天都有点东西写。
今天先积累一个作业题以及记一下这个的思路,以及简单的改进。

题目是这样的:

甲、乙、丙三人同时放鞭炮, 甲每隔 a 秒放一个, 乙每隔 b 秒放一个, 丙每隔 c 秒放一个, 他们各自都放 d 个。对给定的 a、b、c 和 d(a,b,c>0) (d是正整数) 求能听到多少声鞭炮响。 假设两个响声相差小于0.001秒时,人无法区分。

思路非常明确:

  • 设置变量a,b,c,存放甲乙丙的响炮时间间隔
  • 各自放d个炮,设置一个变量d,存放每人放炮总数
  • 要求听到响声的总数,还应当设置一个变量(记为ptCount)记录总共听到多少声炮响

这个想法是首先应当想到的。那么现在的问题就是如何计算每个人的两次炮响时间差是否在0.001s以内呢?

这里我提供一种方法。

一种思路:

  • 因为一共三人,每人放d个鞭炮,所以假设每个人放的每个炮都能被听到的话,一共可以被听到3*d次。
  • 所以我们可以申请一个长度为3*d的一维动态数组来存放每人放炮的时刻。 注意,是时刻!
  • 时刻每次每次都计算,第n次计算出来的时刻要与之前计算出来的(n-1)个时刻每个都比较,若发现差的绝对值在0.001s以内,则该次计算出来的时刻不填入一维数组;如果差的绝对值大于0.001s,那么该时刻填入一维数组,ptCount++.
  • 这里的ptCount还可以代表当前时刻对应在数组里的下标。

话不多说,上代码!

	int  d;
    int ptCount = 0;
    double a,b,c; 
    double tmp = 0;
    cin >> a >> b >> c >> d;

    double* stArray = new double[3 * d];
    bool bF = false;
    for (int k = 0; k < 3 * d; k++)
        stArray[k] = 0;
  • 这段是简要的变量声明。
  • tmp用来存储当下所计算的时刻,后面会用到。
  • bF用来区分某个时刻是不是与之前的某个时刻差在0.001之内
for (int i = 0; i < d; i++)
        {
            tmp = i * a;
            if (ptCount == 0)
            {
            	stArray[ptCount++] = tmp;
            }
            bF = false;
            for (int j = 0; j < ptCount; j++)
            {
                if (fabs(stArray[j] - tmp) < 0.001)
                {
                    bF = true;
                    break;
                }
            }
            if (!bF)   //if(bF==false)
            {
                stArray[ptCount++] = tmp;
            }
        }
  • 这段是计算甲的每个时刻。 开始的那个if(ptCount==0)是判断这个数组里目前有没有被填入数据。 如果真,即没有被填充的话直接填入如果假,即数组中已经有东西了,那么就进行下面的判断。
  • 下面判断自然好判断,内层循环遍历数组的从第0个开始到第ptCount-1个
  • stArray[ptCount++] =tmp类似这种表达式里面,是先用ptCount当前的值计算完表达式之后ptCount才又加了1,所以上面才是“到ptCount-1个”。
  • 里面的break执行的时候表示已经检测到差在0.001之内,就不用进行下面的遍历了,这个时刻不行,赶紧跳出去算下一个时刻。
  • 后面的乙、丙,直接替换a为b,c就好。

亲测,这样可行。

当然,这样的代码也是有问题的

出现的一些问题

我想到的问题,大体就是:

代码太长

我们发现,这个里面如果仅仅是用上面的方法,直接替换a为b,c,这样的话那块儿循环语句相当于要复制粘贴三次。太长了,太麻烦了。

解决的方法:
考虑到 我们其实很懒,少写一点代码就多一点休息的时间 a,b,c其实要连续用到,所以把a,b,c放到数组里方便下面循环的时候遍历(当然有可能是数据结构啥的,有更加充足的理由,也有更加好的解释,也有更加隐含的优点…(还没学到,大佬不喜勿喷))
这样最外层循环只需要控制a,b,c的值,内层循环和内内层循环执行上面那一段循环代码就行了
话不多说继续上代码:

 int  d;
    int ptCount = 0;
    double src[3]; //输入三个浮点数,放入数组,便于循环判断
    double tmp = 0;
    cin >> src[0] >> src[1] >> src[2] >> d;

    double* stArray = new double[3 * d];
    bool bF = false;
    for (int k = 0; k < 3 * d; k++)
        stArray[k] = 0;
  • 看到没?定义的时候定义了个src[3],用来分别存放之前的a,b,c的值
    然后进行下面的操作:
for (int iSrc = 0; iSrc < 3; iSrc++)
    {
        for (int i = 0; i < d; i++)
        {
            tmp = i * src[iSrc];

            if (ptCount == 0)
            {
                stArray[ptCount++] = tmp;
            }
            bF = false;
            for (int j = 0; j < ptCount; j++)
            {
                if (abs(stArray[j] - tmp) < 0.001)
                {
                    bF = true;
                    break;
                }
            }
            if (!bF)   //if(bF==false)
            {
                stArray[ptCount++] = tmp;
            }
        }
    }
  • 看到没?只是多了一个外层的for循环,整个代码会短很多。
  • 这就是改进的方法。

最后,对于我们初学者,有很重要的最后两步
哪两步?

	delete[] stArray;
    stArray = NULL;

这就是我的第一篇博客,也是我总结了最近做的一道题…
还是日积月累的好!写完就感觉自己的记忆更深了!
以后也要尽量多多更博!
Practice makes perfect!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值