问题1: 一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
题目分析:下一村庄没卖出鸭子之前的数量和当前村庄剩余鸭子数满足:
sub(n+1) = sub(n)/2 – 1 ------> sub(n) = (sub(n+1) + 1)*2
算法构造:
定义递归函数int curr_num(int n), 返回当前村剩余的鸭子书, 当n == 8时,结束,返回2。
算法实现(java):
package com.programingmethod.work6;
/**
*
* @author dengyong
* @Description:${通过递归解决卖鸭子的问题}
* @version 1.0
* @date: 2018-11-15
* 问题描述:一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。
* 这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?
* 经过每个村子卖出多少只鸭子?
*/
public class Duck {
/**
* 计算当前村庄剩余的鸭子数
* 原理:
* 下一村庄剩余鸭子数和当前村庄剩余鸭子数满足: sub(n+1) = sub(n)/2 - 1
* ==》sub(n) = (sub(n+1) + 1)*2
* 这就是递推公式
* @param n 经过的村子编号
* @return 该村子当前的鸭子数
*/
public static int curr_n(int n){
int sub_n;// 当前村庄剩余的鸭子的数量
// 递归的出口
if (8 == n){ // 当经过第七个村子的时候,停止递归,剩余两只鸭子
sub_n = 2;
System.out.println("经过第"+n+"个村子还剩"+sub_n+"个鸭子");
return sub_n;
} else {
// sub(n) = (sub(n+1) + 1)*2
sub_n = (curr_n(n+1)+1)*2;
System.out.println("经过第"+n+"个村子"+"共有"+sub_n+"个鸭子,"+"卖了"+(sub_n/2+1)+"个鸭子");
if (1 == n) {
System.out.println("一共赶了: "+sub_n+"只鸭子");
}
return sub_n;
}
}
public static void main(String[] args) {
curr_n(1);
}
}
运行截图:
问题2:角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。
如:输入22,
输出 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1
STEP=16
题目分析: 先对输入的数n进行判断,若 n = 1,则输出1;若输入的数为偶数, 则把它除以2;若为奇数则乘3加1;直到n = 1为止。
算法构造:
当n == 1 , 返回1
若 n%2 == 0, n = n/2 否则 n = n*3+1
算法实现(Java):
package com.programingmethod.work6;
/**
*
* @author dengyong
*
*/
public class ToOne {
/**
* 递归计算的方法
* @param count 计算的次数
* @param n 要计算的数
* @return 1
*/
public int f(int n, int count){
System.out.println(n);
// 当n==1的时候,返回即可, 输出计算次数
if (1 == n){
count += 1;
System.out.println("一共计算了:"+count+"次");
return 1;
} else {
// 如果是偶数
if (0 == n%2){
// 把这个数除2
count += 1; //次数加一
return f(n/2, count);
} else { // 是奇数
count += 1; //次数加一
// 乘3加1
return f(n*3+1, count);
}
}
}
/**
* 方法2:
* 每次执行一次就返回1,用一个计数器将每次执行的加起来即可
* @param n
* @return
*/
public int fCount(int n) {
System.out.println(n);
int count=1;
if (1 == n){
count = 1;
System.out.println("一共计算了:"+count+"次");
} else {
// 如果是偶数
if (0 == n%2){
// 把这个数除2
// 计数器把下一次执行的次数加起来
count += f(n/2, count);
} else { // 是奇数
// 乘3加1
count += f(n*3+1, count);
}
}
return 1; //每执行一次就相当于次数加一
}
public static void main(String[] args) {
ToOne t = new ToOne();
t.f(22, 0);
t.fCount(22);
}
}
运行截图:
问题3:电话号码对应的字符组合:在电话或者手机上,一个数字如2对应着字母ABC,7对应着PQRS。那么数字串27所对应的字符的可能组合就有3*4=12种(如AP,BR等)。现在输入一个3到11位长的电话号码,请打印出这个电话号码所对应的字符的所有可能组合和组合数。
题目分析:0-->() 1--->() 2—>(a, b, c) 3—>(d, e, f) 4--->(g, h, i)….
算法构造:用一个键值对将这些对应关系存储起来,每个电话号码进来后,从第一位开始递归,直到最后一位时开始返回结果。
算法实现(python):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : phoneNumber.py
# @Author: dengyong
# @Date : 2018/11/16 15:46
# @Desc :
"""
3.电话号码对应的字符组合:在电话或者手机上,一个数字如2对应着字母ABC,
7对应着PQRS。那么数字串27所对应的字符的可能组合就有3*4=12种(如AP,BR等)。
现在输入一个3到11位长的电话号码,请打印出这个电话号码所对应的字符的所有可能组合和组合数。
"""
# 存储某个键对应的字母,用一个列表存储
# 列表的下标对应了数字键,内容则是用一个元组存放了这一组字母
char = [(), (), ("A", "B", "C"), ("D", "E", "F"), ("G", "H", "I"),
("J", "K", "L"), ("M", "N", "O"), ("P", "Q", "R", "S"),
("T", "U", "V"), ("W", "X", "Y", "Z")]
# 每个数字键对应的字母个数
char_sum = [0, 0, 3, 3, 3, 3, 3, 4, 3, 4]
def searchGroup(numbers, temp_list, index, lenth):
"""
递归方法体
:param numbers: 电话号码 type-->[list]
:param temp_list: 辅助列表,用于存放某个数字上的字母索引,动态变化的
:param index: 电话号码的索引
:param lenth: 电话号码的长度
:return:
"""
# 当数到最后一位的时候,
if index == lenth:
for i in range(lenth):
print(char[numbers[i]][temp_list[i]], end="\t")
print()
return
else:
# 循环次数为当前数字上的字母数量
for i in range(char_sum[numbers[index]]):
temp_list[index] = i # 当前数字的第一个字母,下一次循环就是当前字母的第二个字母
searchGroup(numbers, temp_list, index + 1, lenth)
if __name__ == '__main__':
number = [4, 9, 6, 6]
answer = [_ for _ in range(len(number))]
searchGroup(number, answer, 0, len(number))
运行截图:
问题4:日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将2520个桔子分给六个儿子。分完 后父亲说:“老大将分给你的桔子的1/8给老二;老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子?
题目分析: 1. 老六得到橘子后分给老大1/3还剩420 则:
设老六得到老五给的橘子后有x个橘子, 则: x(1 - 1/3) = 420 -> x = 630
则老六给了老大x*1/3 = 210
2. 设老大没给老二之前,原本原有x橘子, 则:x(1 - 1/8) + 210 = 420
则: --> x = 240 即老大原本有240个橘子,这就是递归的入口
算法构造:
# (下一个人原有的 + 别人给的)*(1 - 1/(9 - son_num - 1)) = 420
# -->下一个人原有的 = 420/((7-son_num)/(8-son_num)) - 别人给的
def juzi(son_num, history, other_give):
"""
递归函数
:param son_num: 儿子编号
:param history: 之前原有的橘子数量
:param other_give: 别人给他的橘子数量
:return:
"""
算法实现(python):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : origin.py
# @Author: deng
# @Date : 2018/11/16 17:11
# @Desc :递归解决分橘子的问题
"""
问题:父亲将2520个桔子分给六个儿子。分完 后父亲说:“老大将分给你的桔子的1/8给老二;
老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;
老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;
老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。
问: 六兄弟原来手中各有多少桔子?
"""
"""
解题思路:
1. 老六得到橘子后分给老大1/3还剩420 则:
设老六得到老五给的橘子后有x个橘子, 则: x(1 - 1/3) = 420 -> x = 630
则老六给了老大x*1/3 = 210
2. 设老大没给老二之前,原本原有x橘子, 则:x(1 - 1/8) + 210 = 420
则: --> x = 240 即老大原本有240个橘子,这就是递归的入口
"""
def origin(son_num, history, other_give):
"""
递归函数
:param son_num: 儿子编号
:param history: 之前原有的橘子数量
:param other_give: 别人给他的橘子数量
:return:
"""
if son_num > 6:
# 递归出口, 结束
return
else:
# 如果是大儿子, 先给别人, 别人再给他
if son_num == 1:
print("老 %d 原有的橘子数量为: -> %d" % (son_num, history))
# 计算老大给别人的橘子数量
give_other = history/(9 - son_num)
print("老 %d 给出的橘子数量为:-> %d" % (son_num, give_other))
print("老 %d 从老 %d 那得到的橘子数量为: -> %d" % (son_num, 6, other_give))
print("------------------------------------------------------")
# 下一个人的橘子中别人给的=这个人给出去的
other_give = give_other
else:
# 其他儿子都是别人先给他,他再给别人
print("老 %d 原有的橘子数量为:-> %d" % (son_num, history))
print("老 %d 从老 %d 那得到的橘子数量为: -> %d" % (son_num, son_num-1, other_give))
# 计算给别人的
give_other = (history+other_give)/(9-son_num)
print("老 %d 给出的橘子数量为: -> %d" % (son_num, give_other))
print("------------------------------------------------------")
other_give = give_other
# 这里是计算下一个人原有的橘子数量
# (下一个人原有的 + 别人给的)*(1 - 1/(9 - son_num - 1)) = 420
# -->下一个人原有的 = 420/((7-son_num)/(8-son_num)) - 别人给的
history = 420/((7 - son_num)/(8 - son_num)) - other_give
origin(son_num + 1, history, other_give)
if __name__ == '__main__':
# 老大原本有240个橘子, 老六给了210个
origin(1, 240, 210)
运行截图: