今天我在学校上晚自习,然后在机房里刷题。其中有一套C语言题最后一道编程题很有意思,简单记录一下。

记得那个题目是这样的:

输入一本书的页码,第一天读40页,后续每天多读5页。问多少天能读完,最后一天读了多少页。

这是一个很经典的应用题。标准写法应该是……呃我没看好像。
当时的我想要挑战不看答案,自己独立解题。就这样头脑风暴了10分钟以后,最终我“原创”出来了这么一套代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
main()
{
int pages,read=40,i=1;
scanf("%d",&pages);
while(pages > 0)
{
pages -= read;
read += 5;
i++;
if(pages - read <=0) break;
}
printf("days=%d, last=%d",i,pages);
}

这太抽象了,可能只有我能看懂哈哈。
我来解释一下这到底是怎么回事:
1.首先,输入一本书的页面
2.当 要读的页数 大于零的情况下
3.剩余页数是当前页数减去今天读的页数
4.今天读的页数+5,预加载明天要读的页数
5.天数增加
我们把每一次的循环看作每一天所要执行的阅读任务,前面都看起来没问题是吧,奇怪的是如果只写那五步的话结果会出现一个负数。
就在我以为这样写根本行不通想要去找答案的时候,我才终于意识到可能是因为循环边界问题,在差点进入下一次不满足while条件的情况下多计算了一次导致减超。

于是我想出了一个很精妙的办法:在while里最后加一行预测明天的代码。这是最抽象的,也是整个代码里最神的地方。我的思路是既然知道一定会被减超,那我直接在最后检查明天会不会减超不就行了。如果下一天的阅读超过了整本书的页数(减出负数),直接退掉循环让它不会进入下一天。
在这之前,已经+5了,代表下一天的任务。而且pages在这之前已经被减完了,所以这里的pages和read变量都表示明天了,在明天(下一次循环)实际到来之前就预检,达到“预测”的目的。
(我不行了我都快被自己给说绕了)

另外你可能会注意到初始化赋值语句里的i=1那块。那为什么非得等于1,而不是0或者其他?
这里如果不加1的话最终计算出来的天数会少一天,因为是剩最后几页的时候预检明天了,明天并未真正到来(到来了会减超成负数)。所以需要初始化的时候把那一天给补回来。
最终pages被减的差不多了,就是最后那一天剩下的量了。

那话又说回来了,这里while循环的条件其实可以直接写true或1。表示时间可以无限增长,在无限的时间里做出有限操作这个逻辑依然是成立的,因为做完了就不做(break)了。
总之就这样,好好欣赏一下我的课上小设计吧。