题目:海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子平均分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三、第四、第五只猴子都是这样做的,问海滩上原来最少有多少个桃子?
这是采用试探法,由少到多逐渐试探。由题意知,原来的桃子肯定多于 6 个,所以这里由 6 开始,逐渐增加桃子数目,直到 5 只猴子第一次全部分桃成功,则得到的结果就是最少的满足条件的数量。
程序流程图程序:
// 桃总数
var peachAmount = 6
// 剩下的桃的数量
var leftPeachs = 0
// 循环结束标志
var loopVoer = false
while !loopOver {
leftPeachs = peachAmount
for i in 1...5 {
if (leftPeachs - 1) % 5 == 0 {
leftPeachs = 4 * (leftPeachs - 1) / 5
if i == 5 {
// 达到 5 次,试探成功,设置 loopOver 为真以退出 while 循环
loopOver = true
}
} else {
// 试探失败,增加桃子数量,退出 for in 循环,重新开始
peachAmount += 1
break
}
}
}
得到的结果为,原来的桃子数量最少为 3121 个,分完后还剩 1020 个
上面增加桃子数量时,每次只加 1 ,步长值太小。其实因为要被 5 整除,所以可以每次加 5 的。所以增加数量部分可以写成这样:
peachAmount += 5
这样可以减少很多无用功。
其实,可以进一步分析得出,失败于第 2 只猴子时,增加的数量应能被 5(5的1次方) 整除;失败于第 3 只猴子时,增加的数量应能被 25(5的2次方) 整除,以此类推。所以增加数量部分可以进一步写成这样:
peachAmount += Int(pow(Double(5), Double(i - 1)))
这样可以最大限度地降低试探次数。
下面的代码除了作增加数量上的修改,还增加了一个 monkeyAmount(猴子数量) 常量,这样可以使代码更通用一些。比如你测试不同数量的猴子时,只需改这个常量值就可以了。
loopVoer = false
let monkeyAmount = 9
peachAmount = monkeyAmount + 1
while !loopOver {
leftPeachs = peachAmount
for i in 1...monkeyAmount {
if (leftPeachs - 1) % monkeyAmount == 0 {
leftPeachs = (monkeyAmount - 1) * (leftPeachs - 1) / monkeyAmount
if i == monkeyAmount {
loopOver = true
}
} else {
peachAmount += Int(pow(Double(monkeyAmount), Double(i - 1)))
break
}
}
}