韩信点兵双解法

1.问题描述:

话说这天韩信在项王手下吃了败仗,最后带着自己零散的部队撤出了战场。这个时候他想知道自己部队士兵的具体人数(当然他也不可能从项王手下带走超过100位士兵)。聪明的韩信不想直接清点自己军队的人数(再浪费时间估计这些士兵他也带不走了……),于是,他让士兵先后以三人一排、五人一排、七人一排的方式排队,每次排好队后,他只看一眼队伍的排尾人数(分别用a , b, c表示),就知道了总人数。现在聪明的你,如果给你三个非负整数a,b,c,你知道军队的总人数吗?已知总人数不超过100,不小于10。

 

2.问题分析:

首先我们看到这个问题,会第一时刻想到使用循环解决问题。在利用循环之前,首先要判断是否存在非法输入,即队尾士兵的数量,假设是n人一排,队尾数量不可小于0,不可大于等于n(假定队尾士兵数量为0是合法的,这个无伤大雅)。

接下来,通常情况下,我们会使用暴力枚举解决问题,即直接遍历0~100的数字,看哪个符合条件输出即可,当数字大于100还没有找到符合条件的数字,直接输出input error即可。

3.上代码:

#include <stdio.h>
int main(void)
{
	int a, b, c;
	int i;
	scanf("%d,%d,%d",&a,&b,&c);
	//1.先判断是不是存在非法输入 。 
	if(a<0||b<0||c<0||a>=3||b>=5||c>=7){
		printf("input error");
		return 0;
	}
	//2.暴力枚举,遍历10~100,看是否有符合条件的数字,存在则返回数值 。 
	for(i = 11; i < 100; i++){
		if(i%3==a&&i%5==b&&i%7==c){
			if(i>10&&i<100){
				printf("%d",i);
				return 0;
			}
		}
	}
	//3.程序运行到这一步说明没有符合条件的数字,返回即可。 
	printf("No answer"); 
	return 0;
}

4.思考:

在这种情况下,暴力枚举造成的时间上的开销比较大,算法是不是可以进一步的优化?

这实际上是一个数学问题,分析:3、5、7的最小公倍数为105,故目标值不会大于105(105为一个循环)

易知,目标数 % 7 = c,则可设目标数 = 7*i + c, 每次的增量为7,可以大大减少运算量。

5.代码优化如下:

#include <stdio.h>
int main(void)
{
	//分析,3、5、7的最小公倍数为105,故目标值不会大于105(105为一个循环) 
	int a, b, c;
	int i; 
	scanf("%d,%d,%d",&a,&b,&c);
	//1.先判断是不是存在非法输入 。 
	if(a<0||b<0||c<0||a>=3||b>=5||c>=7){
		printf("input error");
		return 0;
	}
	//2.目标数 % 7 = c,则可设目标数 = 7*i + c, 每次的增量为7,可以大大减少运算量。
	i = 7 + c;
	while(i<100){
		if(i%3==a&&i%5==b&&i%7==c){
			if(i>10&&i<100){
				printf("%d",i);
				return 0;
			}
			else{
				printf("No answer");
				return 0;
			}
			//增量为7 
			i += 7;
		}
	}
	//3.程序进行到这一步说明没有符合条件的数字,直接返回即可。  
	printf("No answer");
	return 0;
 } 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值