【听礼炮】在海军节的开幕式上,有 A,B,C三艘军舰要同时开始鸣放礼炮各21响

题目

在海军节的开幕式上,有 A,B,C三艘军舰要同时开始鸣放礼炮各 21 响。已知 A 舰每隔 5 秒放一次,B 舰每隔 6 秒放一次,C 舰每隔 7 秒放一次。假设各炮手对时间的掌握非常准确,请编程计算观众总共可以听到几次礼炮声。

答案:54

代码

#include <stdio.h>
int book[200]={0};
int main()
{	
	// 注意,假设有0秒的概念
	// 换言之,0秒时,A,B,C各自同时发射了礼炮 
	int a=0, b=0, c=0;
	for(int i=1; i<=21; i++)
	{
		book[a]=1;
		a+=5;
		
		book[b]=1;
		b+=6;
		
		book[c]=1;
		c+=7;
	}

	int ans=0;
	for(int i=0; i<=140; i++)
		if(book[i]==1) 
			ans++;
	
	printf("%d", ans);
	
    return 0;
}

代码分析

注意,假设有0秒的概念。也就是说,在第0秒时,ABC同时发射了礼炮。那么,我们关注C,因为C肯定是最晚才放完礼炮的,这点毋庸置疑。C在第7秒时发射第2枚礼炮,在第14秒时发射第3枚礼炮,在第21秒时发射第4枚礼炮。。。类推,在 第140秒时 发射第 21 枚礼炮。

book数组用来标记时刻的,所以它的每个下表都代表一个时刻,所以它至少是 0~140 那么大的范围。例如:book[i]=1,表示第i秒,有人放礼炮了。可能是一个或两个或3个,反正就是有人放礼炮了。

a表示A放礼炮的时刻,b表示B放礼炮的时刻,c表示C放礼炮的时刻。for循环里面,推导出各个人放礼炮的时刻,然后在book[]数组的对应位置标记为1。如果两个人同时放礼炮,那么 book数组的某个下标会被重复两次赋值为1。

所以最后我们只需要统计 [0, 140] 这个区间的1的个数,就知道了观众听了几次炮响。

错误代码

#include <stdio.h>
int book[160]= {0};

int main() 
{
	for(int i=0; i<=140; i++) 
	{
		if(i%5==0)
			book[i]=1;

		if(i%6==0)
			book[i]=1;

		if(i%7==0)
			book[i]=1;
	}


	int ans=0;
	for(int i=0; i<=140; i++)
		if(book[i]==1)
			ans++;

	printf("%d", ans);

	return 0;
}

错误代码分析

上面代码输出为 61,跟正确答案 54 相比 多了。在看完正确的代码的分析,发现错误代码的思路似乎也没问题,为什么就是答案偏大呢?

问题出在了A, B,C结束的时间不一样,C是在第140秒放完最后一炮,B是在第120秒,A是在第100秒。而上面的代码,默认A, B也是在140秒内(不一定是第140秒整)放完。

数学解法

在第0秒时,ABC同时发射了第一枚礼炮。那么,他们分别剩下20枚。那么不难想到,

答案 = 1 + ( 20 × 3 -  重叠的炮响次数 t )

重叠的炮响跟公倍数有关,由于0比较特殊,所以就单独分出来了。

重叠的炮响的次数 t = 5,6的公倍数的个数 + 5,7的公倍数的个数 + 6,7的公倍数的个数 - 5,6,7的公倍数的个数

5,6的公倍数的个数:

5,6的最小公倍数是30,由于A更早发射完(C是在第140秒放完最后一炮,B是在第120秒,A是在第100秒),所以公倍数的个数取决于更早发射完那个人。所以,5,6的公倍数的个数 = 100 /  30 = 3

5,7的公倍数的个数:100 / 35 = 2

6,7的公倍数的个数:120 / 42 = 2

5,6,7的公倍数的个数:100 / 210 = 0

所以,重叠的炮响的次数 t = 3 + 2 + 2 - 0 = 7

所以,答案 = 1 + ( 20 × 3 -  7 )  = 54

  • 38
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值