换种思路去解决,---一道有意思的面试题
题目和代码引用于牛客网,原文网址为https://www.nowcoder.com/question/next?pid=1868636&qid=45185&tid=6243658
题目是这样的:
在最近几场魔兽争霸赛中,赫柏对自己的表现都不满意。为了尽快提升战力,赫柏来到了雷鸣交易行并找到了幻兽师格丽,打算让格丽为自己的七阶幻兽升星。经过漫长的等待以后,幻兽顺利升到了满星,赫柏很满意,打算给格丽一些小费。
赫柏给小费是有原则的:
1.最终给格丽的钱必须是5的倍数;
2.小费必须占最终支付费用的5%~10%之间(包含边界)。
升星总共耗费A魔卡,赫柏身上带了B魔卡,赫柏想知道他有多少种支付方案可供选择。
注:魔卡是一种货币单位,最终支付费用=本该支付的+小费
化成简单的表达就是设有3个变量Final,Should,Tip 。Final代表最终支付费用,Should代表本应该支付的,Tip代表小费。
则:Final = Should + Tip ; 且满足 Final为5的倍数, Tip为Final的5%-10%(包含边界)
我们很容易就想到用循环来进行枚举,找到合适的结果就+1,最终输出结果,
现在来看一个不用循环的代码:
1 #include<iostream> 2 #include<math.h> 3 using namespace std; 4 int main(){ 5 int A,B,R; 6 while(cin>>A&&cin>>B){ 7 R=0; 8 int a=ceil(A/0.95),b=floor(A/0.9); 9 if(a<=B){ 10 if(b>B){ 11 R=B/5-a/5; 12 }else{ 13 R=b/5-a/5; 14 } 15 if(a%5==0) 16 R++; 17 } 18 cout<<R<<endl; 19 } 20 return 0; 21 }
首先得到A,B ,A为应该支付的费用,这是确定的。 B为赫柏身上所带的费用。现在我们换种思路,A是确定的,小费所占的比例为5%-10%,那么可以反过来知道,应该支付的也就是A占总费用的90%-95%,那么便可以算出总费用的范围。在代码中,a为A占总费用的95%也就是小费占5%的数值, b为A占总费用的90%也就是小费占10%的范围;
对于ceil()和floor()函数分别为向上取整,和向下取整。 作为总费用的起点,将算出的值向上取整,比如为5.6,那么肯定取6,因为5肯定不符合,同样的道理,
对于b来说,作为总费用的终点.比如b取值为5.6。肯定可以达到5,而6是达不到的,所以想下取整。
首先判断赫柏身上所带的费用B和总费用的起点比,如果B小于a,那么说明钱没带够,也就是说没法支付小费了,直接退出循环。
如果赫柏带的钱B大于等于总费用的起点a,那么再看赫柏的钱和总费用的终点b相比怎么样,如果B大于等于b那么 则 方案总数= b/5-a/5(咱们后边在来说这个是怎么算的)
如果赫柏带的钱B<b那么就按总费用为a到B来计算,也就是方案总数 = B/5-a/5
现在再来看这个方案总数 = b/5-a/5 是怎么算的,这里以赫柏的钱带够了来看,没带够一样的道理,因为最后要求最终付的钱为5的倍数,也就是说总费用每一次+5,每加一次5就是一次新的支付方案,那么求出费用的初始点a用了几个5,在求出终点b用了几个5,他们之差就是多了几个5,也就是有几种方法,由于这样计算吧a是5的倍数的情况也减去了,而a为5的倍数,也就是小费为5%时也是一种情况,所以最后计算时,要把这情况加上,即程序中的R++,最后输出结果R,也就是方案的总数。
其实还有一个问题没有解决,就是b/5-a/5能不能用(b-a)/5来替换? 假设b-a=5.6,然后除以5等于1,得出结果,但此时并没有考虑a的值,换而言之,这样计算的话没有在满足大于等于a的5的倍数上开始+5,而不管基础就开始在a的基础上加,这样是不正确的。比如刚开始为1,然后加5等于6,你在计算的时候,就会把6当成一种方案计算进去,而真正开始进行加5的应该是5,然后是10,而不是6,11,。再换而言之,(b-a)/5,是对两者的差来进行计算有几个5,没有考虑基础的情况。