蓝桥杯(数字游戏)

回溯算法(全排列问题):

数字游戏

问题描述
  给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
  例如:
  3 1 2 4
  4 3 6
  7 9
  16
  现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。
输入格式
  第1行为两个正整数n,sum
输出格式
  一个1~N的一个排列
样例输入
4 16
样例输出
3 1 2 4
数据规模和约定
  0<n<=10

1、 杨辉三角的第N行与该题的最初序列a[i]之积为最后得到的数字sum。如(1 3 3 1)*(3 1 2 4)=16

杨辉三角
1
1 1
1 2 1
1 3 3 1

2、 由1可知,我们只要找出N的全排列,并与杨辉三角的第N行相乘,如果和为sum,则将其筛选出来,得到a[i]。由于题目是找字典序最小的一个,因此我们从小到大搜索,当满足要求,则返回结果,不再继续搜索。此时我们需要解决两个问题,首先是返回杨辉三角的最后一行,其次是全排列问题,全排列可以用回溯算法。
返回杨辉三角的最后一行
#返回杨辉三角的最后一行
N=int(input())
l=[[0 for i in range(N)]for j in range(N)]
def yh(l):
    for i in range(N):
        for j in range(N):
            if i==0 and j==0:
                l[i][j]=1
            elif j==0:
                l[i][j] = 1
            elif j==i:
                l[i][j]=1
            else:
                l[i][j]=l[i-1][j-1]+l[i-1][j]
    return l[N-1]
找1-N个数的全排列

用一个数组V标记已使用过的数字,单层搜索时遍历v数组,当遇到v[i]为0 时,将nums[i]加入路径,并进行递归搜索,当走到叶子节点时,撤销处理结果,开始回溯。在这里插入图片描述

# 找1-N个数的全排列
l=list(map(int,input().split()))
v=[0 for i in range(len(l))]
path=[]#存放单个排列
res=[]#存放全部排列结果
def huisu(step,l):
    #找递归终止条件,当到叶子节点时返回,开始回溯
    if step==len(l):
        res.append(path.copy())
        return

    #单层搜索
    for i in range(len(l)):
        if v[i]==1:
            continue
        v[i]=1
        path.append(l[i])
        huisu(step+1,l)
        path.pop()#撤销处理结果
        v[i]=0

huisu(0,l)
print(res)

测试结果:
1 2 3
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

针对该题,我们要得到的是满足一定要求的排列,因此要设一个参数insum,路径里面每加入一个数就更新一次(进入一层更新一次),直到进入最后一层,即到达叶子节点,判断当前的和insum是否满足题意:
N,sum=map(int,input().split())
l=[[0 for i in range(N)]for j in range(N)]
def yh(l):
    for i in range(N):
        for j in range(N):
            if i==0 and j==0:
                l[i][j]=1
            elif j==0:
                l[i][j] = 1
            elif j==i:
                l[i][j]=1
            else:
                l[i][j]=l[i-1][j-1]+l[i-1][j]
    return l[N-1]

# 找1-N个数的全排列
v=[0 for i in range(N+1)]
path=[]#存放单个排列
res=[]#存放全部排列结果
y=yh(l)#杨辉三角的最后一行
flag=0
def huisu(step,insum):
    global flag
    if flag==1:
        return
    #找递归终止条件,当到叶子节点时返回,开始回溯
    if step==N:
        if insum==sum:
            # res.append(path.copy())
            print(' '.join(map(str,path)))
            flag=1
        return

    #单层搜索
    for i in range(1,N+1):#i从1开始
        if v[i]==1:
            continue
        v[i]=1
        path.append(i)
        tsum=insum+i*y[step]#计算路径里面加入一个数时当前的和。在每一层进行更新
        huisu(step+1,tsum)
        path.pop()#撤销处理结果
        v[i]=0

huisu(0,0)
# print(res)

测试结果:
4 16
3 1 2 4

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值