递归的总结思考及相关题

本文介绍了递归的关键要素,并通过N皇后问题、2N皇后问题、上台阶问题和放苹果问题展示了递归和回溯算法的解决策略。在N皇后问题中,通过逐行放置皇后并检查冲突来找到解决方案;2N皇后问题则是在解决黑棋布局后放置白棋。此外,文章还探讨了一个错误的表达式解析代码,分析了其出错原因。同时,文章讨论了上台阶问题的斐波那契数列解法,以及如何在有限的盘子中放置苹果的组合问题。
摘要由CSDN通过智能技术生成

目录

小结

N皇后

2N皇后

表达式    一个错误的代码,还没弄懂

上台阶

放苹果


小结:

在求解f(n, other variables)的时候,我们直接默认f(n - 1, other variables)已经算完就可以了

递归的关键有两个:

(1)递归的结束条件

(2)递归最后一层和其他有关系的层的关系怎样用非递归函数来表达

 画叉树图,初始多少叉后续将递归多少次
遇到return后触底反弹

4-3-2-1(return)-2-3-4

遇到return后就回到上一个函数,然后接着调用函数之下执行(调用函数前的函数不再执行)用栈理解:先进后出,即后进先出

N皇后

思路:

一行一行找;第一行可以任意放,确定第一行后就确定了第二行,也就确定了第三行。。。

要是能找到最后一行,也就是方案成立了。


n= int(input())
pos=[None for i in range(n)]

def isvalid(pos,k,i):   #检查是否可以放,k行之前,0~k-1行进行搜索
    for j in range(k):
        if pos[j]==i or abs(pos[j]-i)==abs(k-j):   #对角线上:行的差的绝对值=列的差的绝对值
            return False
    
    return True

def queen(k):
    if k==n:
        for i in pos:
            print(i+1,end=' ')
        print()
        return
    for i in range(n):  
        if isvalid(pos,k,i):
            pos[k]=i
            queen(k+1)

            
queen(0)

对角线上:行的差的绝对值=列的差的绝对值

或者不把isvaild写成函数。。不过其实都一样

n= int(input())
pos=[None for i in range(n)]


def queen(k):
    if k==n:
        for i in pos:
            print(i+1,end=' ')
        print()
        return
    for i in range(n):  
        for j in range(k):
            if pos[j]==i or abs(pos[j]-i)==abs(k-j): break   #注意这里要对前面每一行都进行检查
        else:
            pos[k]=i
            queen(k+1)

            
queen(0)

又或者,在题目中有不可摆放位置时 

n = int(input())
pos=[n for i in range(n)]
board=[input() for i in range(n)]
sum=0
def queen(k):
    global sum
    if k==n:
        sum+=1
        return 

    for i in range(n):
        if board[k][i]=='.':continue
        for j in range(k):
            
            if pos[j]==i or abs(pos[j]-i)==abs(k-j):break
        
        else:     
            pos[k]=i
            queen(k+1)
            
        

queen(0)
print(sum)





2N皇后

思路:

在放完黑棋后再放白棋

n=int(input())
board=[list(map(int,input().split()))for i in range(n)]   
pos=[n for i in range(n)]     #分别记录白棋和黑棋放的位置
pos_w=[n for i in range(n)]
s=0

def isvalid(pos,k,i):
    for j in range(k):
        if pos[j]==i or abs(pos[j]-i)==abs(k-j): 
            return False
    return True

def queen(k):
    if k==n:
        whitequeen(0)
        return 
    
    for i in range(n):
        if board[k][i]==0:continue
        if isvalid(pos,k,i):
            pos[k]=i 
            queen(k+1)

def whitequeen(k):
    global s
    if k==n:
        s+=1
        return 
    for i in range(n):
        if board[k][i]==0 or pos[k]==i:continue
        if isvalid(pos_w,k,i):
            pos_w[k]=i
            whitequeen(k+1)
            
queen(0)
print(s)

表达式    一个错误的代码,还没弄懂

表达式:通过项加减组成

项:由因子乘除组成

因子:一个数 或 一个表达式放在括号里

例如:(2+3)*(5+7)+9/3

(2+3)9、3 :因子

括号内的2+3 是一个表达式


一个错误的代码:

s=list(input())
def expression(s):
    result=term(s)
    next=s[0]
    while next=='+'or next=='-':
        s.pop(0)
        if next=='+':result+=term(s)
        else:result-=term(s)
        next=s[0]
    return result

def term(s):
    result=factor(s)
    next=s[0]
    while next=='*'or next=='/':
        s.pop(0)
        if next=='*':result*=factor(s)
        else:result/=factor(s)
        next=s[0]
    return result
def factor(s):
    result=0
    if s[0]=='(':
        s.pop(0)
        result=expression(s)
        s.pop(0)
    else:
        while type(int(s[0]))==int:
            result=result*10+int(s[0])
            s.pop(0)
    return result

print(expression(s))

报错:

<ipython-input-62-3b2459bb7ff8> in factor(s)
     26         s,pop(0)
     27     else:
---> 28         while type(int(s[0]))==int:
     29             result=result*10+int(s[0])
     30             s.pop(0)

ValueError: invalid literal for int() with base 10: '+'

是因为28行的得到的是s[0]不是一个可以转换为int的字符,也就是说这里的s[0]不是数字,而是其他符号。。。不知道前面哪里错了哭。

上台阶

思路:

n级台阶的走法:每次要么走1级,要么走2级

先走1级后,剩下n-1级台阶

先走2级后,剩下n-2级台阶

因此每次走均有f(n)=f(n-1)+f(n-2)=走1级后的走法+走2级后的走法

边界条件:

3种都可以:

①n<0  0       n=0  1

当n为负数时,不存在可以走的楼梯就是0;当n为0时,f(1)=f(0)+f(-1),可知f(0)=1

②n=0 1       n=1 1

③n=1 1       n=2 2

n=int(input())
def stair(n):
    if n==1:return 1
    if n==2:return 2
    else:
        return stair(n-1)+stair(n-2)
print(stair(n))

放苹果

思路:(与上台阶的做法很相似,都是分情况)

m个苹果放n个盘子里

1.若m<n,即苹果个数少于盘子个数,那么肯定至多只有m个盘子有苹果可以放,因为多出的盘子都是空盘,就不用考虑了。f(m,n)=f(m,m)

2.若m>=n,可分为有空盘和没空盘的情形

①有空盘:也就是说有n-1个盘子可以考虑放    f(m,n-1)

②没有空盘:即至少每个盘子都要放一个,还剩下m-n个苹果要考虑放:f(m-n,n)

           因此m个苹果放n个盘子里f(m,n)=f(m,n-1)+(m-n,n)

边界条件:

m=0   1     0个苹果,可以表示所有盘子里都不放苹果,也是一种放法 (这里是不是也可以联想上台阶中当n=0时,也有一种走法)

n=0   0      没有盘子了,就没得放

m,n=map(int,input().split())

def f(m,n):
    if m<n:return f(m,m)
    if m==0:return 1
    if n==0:return 0
    
    return f(m,n-1)+f(m-n,n)

print(f(m,n))

算24     (未解决,代码错误)

题目描述:

给出4个小于10的正整数,使用加、减、乘、除4种运算以及括号把4个数连接起来得到一个结果等于24的表达式。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬

这里加、减、乘、除以及括号的运算结果和运算优先级跟平常定义一致。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬

         例如,对于5,5,5,1,可知5×(5-1/5)=24。又如,对于1,1,4,2无论如何都不能得到24

输入格式

     在代码中的输入部分输入4个小于10的正整数。

输出格式

      对于每一组测试数据,输出一行,如果可以得到24,输出"YES"其算法;否则“NO”。



思路:

首先必定要选取两个数进行计算,在4个数中任选取2个数,用枚举。

数与数运算之间考虑用哪种运算符号

两个数进行运算完后与剩下的n-2数进行计算,相当于一共n-1个数做运算。(此处便是一个递归过程),在这n-1个数里面又任意选取两个数....

终止条件:

当n=1,即只剩下一个数了,便相当于最后的结果,看这个结果是否为24


一个错误的代码:

l=list(map(int,input().split()))
new=[]
def ca(list,n):
    global new
    if n==1:
        if int(new[0])==24: 
            return True
        else:
            return False
        
    for i in range(n-1):
        for j in range(i+1,n):
            for k in range(n):
                if k!=i and k!=j:
                    new.append(list[k])                    
            new.append(list[i]+list[j])
            if ca(new,n-1):return True
            new.pop()
            new.append(list[i]-list[j])
            if ca(new,n-1):return True
            new.pop()
            new.append(list[j]-list[i])
            if ca(new,n-1):return True
            new.pop()
            if list[i]!=0:
                new.append(list[j]/list[i])
                if ca(new,n-1):return True
                new.pop()
            if list[j]!=0:
                new.append(list[i]/list[j])
                if ca(new,n-1):return True
                new.pop()
            new.append(list[j]*list[i])
            if ca(new,n-1):return True
            new.pop()
    return False  
            
if ca(l,4):
    print('Yes')
else:print('NO')

            

熄灯问题

result:开关的状态

用数字表示一行灯的状态:一个数字代表一个二进制:从0-31

getbit(该行的状态,该行第几个灯):即一行中的第j位

v就代表getbit的位置

如果v=1:该行第i位为1

如果v=0:该行第i位为0

对第一行开关状态进行枚举:因为第一行的开关状态是可以自己决定的,就由枚举来决定。而后每一行都由其前一行决定,也就是说第一行的状态决定后,后面的状态也就唯一了。

用switchs代表当行开关的状态。即从0~31

然后当前行i的每一个灯j:如果这个灯为1,那就要关掉:即进行一次翻转 if(getbit())==1:....

if i<5:light(i+1)^=switchs   switchs表示的是第i行的状态,若第i行的第j个灯为1,说明刚才对第j个灯进行了操作,也就是说第i+1行的第j个灯就会受到影响,与其原来状态相反:如果为0,说明第i行的这个灯不需要操作,所以i+1行的灯也不会变化。(0与任何数^异或都是这个数本身,即没有变化)

最后

因为第i行灯的状态是什么,下一行开关的状态就是什么(只有这样才会使第i行的灯给灭掉),因此下一行的开灯状态switch应该就是这行的lights的状态

走完j这个循环,再回到i的循环,进入下一行:就有了新的这行的result开灯状态存为switch

每次存的是switch!代表开关状态

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值