学Python的第八天---递归与递推

一、递归实现指数型枚举

在这里插入图片描述

写法一:dfs

这是一个深度优先搜索(DFS)的示例程序,用于生成所有长度为 1 到 n 的子集。具体地,程序定义了一个名为 dfs 的函数,该函数用于递归地生成所有子集。在每个递归调用中,函数从当前位置 u 开始,尝试向下遍历到位置 n + 1。在遍历到每个位置时,函数将该位置添加到 path 列表中,然后递归调用 dfs 函数以继续向下遍历。当到达位置 n + 1 时,函数将会停止递归并返回。在每个递归调用结束后,函数会将 path 列表中的最后一个元素删除,以便在下一个递归调用中正确地生成子集。

最后,主函数调用 dfs(1) 函数来生成所有长度为 1 到 n 的子集,并将每个子集打印到控制台。该程序对于学习 DFS 算法和子集生成算法是一个很好的参考和实践。

n = (int)(input())
path = []
def dfs(u):
    print(" ".join(str(i) for i in path))
    if u == n + 1: return
    for i in range(u, n + 1):
        path.append(i)
        dfs(i + 1)
        path.pop()

dfs(1)

写法二:python库函数

combinations(ls,i)

会返回一个长度为 i 的元素组成的组合,其中的元素是从 ls 中选取的,而且这些元素的顺序是按照 ls 中的元素顺序来的。比如说,ls = [“1”, “2”, “3”],那么 combinations(ls, 2) 就会返回 [(“1”, “2”), (“1”, “3”), (“2”, “3”)] 这个列表,其中的每个元素都是一个长度为 2 的元组,表示选取了两个元素组成的组合,而且这两个元素在 ls 中的顺序是不变的。

from itertools import *
n = int(input())
ls = []
for i in range(1,n+1):
    ls.append(str(i))
for i in range(n+1):
    for element in combinations(ls,i):
        a = " ".join(element)
        print(a)

二、递归实现排列型枚举在这里插入图片描述

自己的写法

n=int(input())
st=[False]*10
path=[]
def f(u):
    if u==n:
        print(" ".join(str(i) for i in path))
    for i in range(1,n+1):
        if st[i]==False:
            st[i]=True
            path.append(i)
            f(u+1)
            st[i]=False
            path.pop()
f(0)

三、递归实现组合型枚举

在这里插入图片描述
自己的写法

n,m=map(int,input().split())
st=[False]*30
def f(u,t):
    if t==m:
        for i in range(1,len(st)):
            if st[i]==True:
                print(i,end=' ')
        print()
        return
    for i in range(u,n+1):
        if st[i]==False:
            st[i]=True
            f(i,t+1)
            st[i]=False
f(1,0)

四、翻硬币

在这里插入图片描述

a,b=input(),input()
ans=0
a=[i for i in a]
b=[i for i in b]
for i in range(len(a)):
    if a[i]!=b[i]:
        a[i+1]=('o' if a[i+1]=='*' else '*')
        ans+=1
print(ans)

五、数的计算

在这里插入图片描述

h=[0]*1000
n=int(input())
for i in range(1,n+1):
    h[i]=1
    for j in range(1,i//2+1):
        h[i]+=h[j]
print(h[n])

六、费解的开关

在这里插入图片描述
在这里插入图片描述

import copy
g=[[0 for i in range(5)]for j in range(5)]
gg = [[0 for i in range(5)]for j in range(5)]
n=int(input())
dx=[1,0,-1,0,0]
dy=[0,1,0,-1,0]
def turn(x,y):
    for i in range(5):
        x1=x+dx[i]
        y1=y+dy[i]
        if x1<0 or x1>=5 or y1<0 or y1>=5:
            continue
        if g[x1][y1]=='1':
            g[x1][y1]='0'
        else:
            g[x1][y1]='1'

for _ in range(n):
    for i in range(5):
        g[i]=list(input())
    if _<n-1:#读入换行符
        c=input()
    gg=copy.deepcopy(g)
    res=19999#记录答案,最小步数
    for x in range(32):#5个1,枚举每种变换情况
        stp=0
        for i in range(5):
            op=x>>i&1
            if op==1:
                turn(0,i)#先定第一排怎么改变的
                stp+=1
        for i in range(4):
            for j in range(5):
                if g[i][j]=='0':
                    turn(i+1,j)#如果这一行是灭的话,那么就按下一行的灯
                    stp+=1
        flag=1
        for i in range(5):
            if g[4][i]=='0':
                flag=0
                break
        if flag==1:
            res=min(res,stp)
        g=copy.deepcopy(gg)
    if res>6:
        print(-1)
    else:
        print(res)


七、飞行员兄弟


感觉这类题差不多可以理解了,这个跟上面是一种题型,我参考的也是同一个人写的,感觉他写的很清晰!

import copy
g=[[0 for i in range(4)]for j in range(4)]
change = [[0 for i in range(4)]for j in range(4)]
dis=[]
ans=[]
def get(x,y):
    return 4*x+y

st=0
for i in range(4):
    g[i]=list(input())
    for j in range(4):
        if g[i][j]=='+':
            st+=1<<get(i,j)#记录现在的情况
for i in range(4):
    for j in range(4):
        for k in range(4):
            change[i][j]+=(1<<get(k,j))+(1<<get(i,k))#记录变化一个地方的改变
        change[i][j]-=(1<<get(i,j))
res=100
for i in range(1<<16):#多种不同的翻转方式
    now=st
    dis.clear()#记录路径
    for j in range(16):
        op=i>>j&1
        if op==1:
            x=j//4
            y=j%4
            now^=change[x][y]
            dis.append([x+1,y+1])
    if now==0 and len(dis)<res:
        res=len(dis)
        ans=copy.deepcopy(dis)
print(res)
for i,j in ans:
    print(i,j)

八、带分数

在这里插入图片描述
这一道题的话,我就是看了两个写法,我感觉我看python的代码,我觉得我下次还能写出来,但是看C++的话,我就觉得我一定写不出来哈哈哈哈

然后我是看这两个写法感觉还是不错滴!

写法一:

这个我感觉跟那个全排列还是很像的,然后他就是将数字全排列,然后

n = int(input())
ans = 0
used =[False for i in range(10)]
res = []
def check(res):
    a=0
    for i in range(0,len(res)-2):
        a=a*10+int(res[i])
        b=0
        if a<n:
            for j in range(i+1,len(res)-1):
                b=b*10+int(res[j])
                c=0
                for z in range(j+1,len(res)):
                    c=c*10+int(res[z])
                if (a+b/c)==n:
                    global ans
                    ans+=1

def backtrack(st):
    if st == 10:
        check(res)
        return
    for i in range(1,10):
        if used[i]:
            continue
        used[i] = True
        res.append(i)
        backtrack(st+1)
        res.pop()
        used[i] = False

backtrack(1)
print(ans)

写法二:

n = int(input())


def dfs_c(a, c):
    b = c*(n-a)
    if len(str(b)+str(a)+str(c))>9: return

    if set('123456789')==set(str(a)+str(b)+str(c)) and len(str(b)+str(a)+str(c))==9:
        global res
        res += 1

    for i in range(1, 10):
        if i not in use:
            use.add(i)
            dfs_c(a, c*10+i)
            use.remove(i)

def dfs_a(a):
    if a>=n:
        return
    if a:
        dfs_c(a, 0)

    for i in range(1, 10):
        if i not in use:
            use.add(i)
            dfs_a(a*10 + i)
            use.remove(i)


res = 0
use = set()
dfs_a(0)
print(res)

九、砖块

在这里插入图片描述
接下来我将展示不同的几种写法,我觉得都蛮好的!

写法一:

这个方法不是最优解,但是我觉得他的写法很棒,值得学习!
暴力法

change={
    
    'B':'W','W':'B'}
for _ in range(int(input())):
    N=int(input())
    line=list(input())[:N]
    if 'W' not in line or 'B' not in line:
        print('0')
    else:
        result=[]
        for i in range(N-1):
            if line[i]=='B':
                line[i],line[i+1]='W',change[line[i+1]]
                result.append(i+1)
        if line[-1]=='W':
            print(f"{
      
      len(result)}\n{
      
      ' '.join(map(str,result))}")
        else:#如果最后不是W,说明要翻转B
            for i in range(N-1):
                if line[i]=='W':
                    line[i],line[i+1]='B',change[line[i+1]]
                    result.append(i+1)
            if line[-1]=='B':
                print(f"{
      
      len(result)}\n{
      
      ' '.join(map(str,result))}")
            else:print('-1')

写法二:

是最优解

t=int(input())
def getcnt(pos,arr):
    res,en=0,[]
    for i in range(len(arr)-1):
        if arr[i]==1-pos:
            arr[i]=pos
            arr[i+1]=1-arr[i+1]
            res+=1
            en.append(i+1)
    return (1000,-1)if arr[len[arr]-1]!=pos else (res,en)
for _ in range(t):
    n=int(input())
    a=input()
    b=[1 if i=='W' else 0 for i in a]
    c=b[:]
    left=[getcnt(0,c),getcnt(1,b)]#讨论两种情况,全部反转为'w',或者全部反转为'B'
    left.sort(key=lambda x:x[0])#按照第一个关键词排序
    if left[0][0]<10000:
        print(left[0][0])
        for i in left[0][1]:
            print(i,end=' ')
        print()
    else:
        print(-1)

十、数的遍历

在这里插入图片描述
在这里插入图片描述
首先,代码通过输入得到二叉树的后序遍历和中序遍历结果,通过遍历中序遍历结果并用一个字典记录下各个节点在中序遍历结果中的位置,这样可以在后序遍历结果中找到每个节点在中序遍历结果中的位置,进而确定左右子树的范围。

然后,代码创建一个队列 que 用于广度优先遍历二叉树,初始将整个二叉树的范围加入队列,每次从队列中取出一个范围,将其中的后序遍历结果中的最后一个节点作为根节点,然后在字典中查找该根节点在中序遍历结果中的位置,以此确定左子树和右子树的范围,如果左子树范围不为空,则将左子树的范围加入队列,如果右子树范围不为空,则将右子树的范围加入队列,最后将根节点加入结果列表中。

最后,代码将结果列表中的数字用空格隔开输出即为先序遍历结果。

from collections import deque

N = int(input())
postOrder = [*map(int, input().split())]
inOrder = [*map(int, input().split())]
find = {
    
    }
for i, inOrder_i in enumerate(inOrder):
    find[inOrder_i] = i

que, result = deque([(0, N-1, 0, N-1)]), []
while que:
    post_l, post_r, in_l, in_r = que.popleft()
    root_value = postOrder[post_r]
    in_i = find[root_value]
    l_len, r_len = in_i - in_l, in_r - in_i
    if l_len:
        que.append((post_l, post_l + l_len - 1, in_l, in_i - 1))
    if r_len:
        que.append((post_r - r_len, post_r - 1, in_i + 1, in_r))
    result.append(str(root_value))
print(' '.join(result))

写法二:bfs

n = int(input())

a = list(map(int, input().split()))
b = list(map(int, input().split()))
lc = [0]*(n+1)
rc = [0]*(n+1)

def p(l, r):
    if len(l) == 1:
        return l[0]
    elif len(l) == 0:
        return 0
    i = 0
    while l[i] != r[-1]:
        i += 1
    v = l[i]

    rc[v] = p(l[i+1:], r[i:-1])
    lc[v] = p(l[:i], r[0:i])
    return v

def bfs(x):
    q = []
    q.append(x)
    print(x, end = ' ')

    while q:
        t = q.pop(0)
        if lc[t]:
            q.append(lc[t])
            print(lc[t], end = ' ')
        if rc[t]:
            q.append(rc[t])
            print(rc[t], end = ' ')
        # print(q)

p(b, a)

bfs(a[-1])

猜你喜欢

转载自blog.csdn.net/qq_51408826/article/details/129447740