韩信点兵C语言实现的几种方法
问题描述:
相传韩信才智过人,从不直接清点自己军队的人数,只要让士兵先后以三人一排、五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总人数了。输入3个非负整数a,b,c ,表示每种队形排尾的人数(a<3,b<5,c<7),输出总人数的最小值(或报告无解)。已知总人数不小于10,不超过100 。
输入
输入3个非负整数a,b,c ,表示每种队形排尾的人数(a<3,b<5,c<7)。
输出
输出总人数的最小值(或报告无解,即输出No answer)。实例,输出:89
样例输入:
2 1 6
样例输出:
41
样例输入:
2 1 3
样例输出:
No Answer
分析:
从问题描述中可以看出,队尾人数等于士兵总人数除以每排士兵基数的余数。
解决思路:
选取一个整数,分别用选取的整数除以每个队形的每排士兵基数,得到每个队形的队尾人数,如计算出的所有队尾人数与题目中给出的队尾一致,若忽略最小值则找到了答案。
难点:
对于这个问题,已经找到了解决思路,但是如何选取整数十分重要,因为这将关系到我们程序的运行快慢。
方法一:
因为我们要找满足条件的最小值,所以我们采用循环的方式,从最小值10开始,然后加1,最大到最大值100,循环91次,如果找到便输出满足条件的最小值并结束循环。
#include<stdio.h>
int main()
{
int a, b, c;
scanf("%d%d%d", &a,&b,&c);
for(int i=10; i<101; i++)
{
if(i%3 == a)
{
if(i%5 == b)
{
if(i%7 == c)
{
printf("%d", i);
return 0 ;
}
}
}
}
printf("No answer");
return 0;
}
方法二:
针对方法一,我们做出如下改进,每排士兵基数最大为7,此时队尾人数为c,所以士兵总人数为7i+c(i为正整数),因此我们的循环从7+c开始,每次加7,最大到91+c或98+c为止,循环只有13或14次,较方法一减少大量运行时间。如果找到便输出满足条件的最小值并结束循环。(为什么不选择每排士兵基数最小3?大家思考一下)
#include<stdio.h>
int main()
{
int a, b, c;
scanf("%d%d%d", &a,&b,&c);
for(int i=7+c; i<101; i=i+7)
{
if(i%3 == a)
{
if(i%5 == b)
{
if(i%7 == c)
{
printf("%d", i);
return 0 ;
}
}
}
}
printf("No answer");
return 0;
}
方法三:
继续对方法二改进:
(1) 若c%3=a,设总人数为7i+c(i为正整数),(7i+c)%3=(7i%3+c%3)%3=(7i%3+c)%3=7i%3+b=b,则有7i%3=0,i=3n,所以总人数为21n+c。
此时,循环从21+c开始,每次加21,最大到84+c为止,循环只有4次,较方法二更加节省时间。
(2)若b%3=a,…,总人数为15n+b。
(3)若c%5=b,…,总人数为35n+c。
(4)若a%5=b,…,总人数为15n+a。
(5)若b%7=c,…,总人数为35n+b。
(6)若a%7=c,…,总人数为21n+a。
程序中只加入了(1)部分,其他部分也可加入,不过看起来程序特别长,但是执行效率在某些时候还是比较高效的。
#include<stdio.h>
int main()
{
int a, b, c;
scanf("%d%d%d", &a,&b,&c);
if(c%3 == a)
{
for(int i=21+c; i<101; i=i+21)
{
if( i%5 == b)
{
printf("%d", i);
return 0 ;
}
}
printf("No answer");
return 0;
}
for(int i=7+c; i<101; i=i+7)
{
if(i%3 == a)
{
if(i%5 == b)
{
if(i%7 == c)
{
printf("%d", i);
return 0 ;
}
}
}
}
printf("No answer");
return 0;
}