目录
小结:
在求解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!代表开关状态