题目

问题描述

给定一个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

感觉这题目不够规范呀:n和N都出现了,应该统一字母的;也用了sum作为变量声明,在python中sum是一个函数,应避免使用函数名作为变量名,也没有给出最后数字s的取值范围…除此以外还要区分开题目中“一个1~N的排列”,“1~N的一个排列”,“一个1~N的一个排列”的意思,因为理解错题目,我还特地在问答区求助了,呜呜呜,说多都是泪…

分析

我们看一下题目,他大致的意思就是给一个数字n,通过1 ~ n的各种排列(假设n是5,那么就是1,2,3,4,5的各种排列)不断两两相加最终得到一个数,如果这个数与总和值相等,那么就返回这个排列,存在多个序列时返回字典序最小的序列。([2,1,3],[1,3,2],[3,1,2]中字典序最小的序列是[1,3,2])。

最容易想到的做法是按字典序由低到高不断穷举每一个序列,让每一个序列不断两两求和相加,最终得到一个数,让这个数与目标值比较看是否相等,若相等,则直接返回该序列,否则继续让下一个序列相加计算,直到遇到符合条件的序列为止。这种方法可以拿到70分,不想在这题浪费太多时间的同学,这么做足够了。

穷举每一个序列,一般就是使用DFS来寻找的。就我而言,我尝试过很多方法去优化上面的算法均已失败告终,(AC拿的真不容易啊!!)即使在遍历搜索过程中添加了如当序列两两相加的值大于目标值时,提前终止递归的条件,还是只能拿个70分。说明这条题还是得找出规律才能更深层次的优化此算法。

这道题跟杨辉三角有异曲同工之妙,都是一个数的值等于它左右肩膀值之和,如果看这道题例子的同时,结合杨辉三角一起看,各位就能找出其中的规律了。

字看不清没关系,图看的清吧?看得清我就要说了。咳咳,ab图中的每一行对应元素相乘之和相等。 这条件相当good,有了它,不会再有中间商赚差价,直接一步到位。

思路

得知本题与杨辉三角有密不可分的关系后,我们就能通过杨辉三角来优化搜索算法了。

因为我们穷举是穷举最后一行序列,也就有n个元素,所以我们也要获取杨辉三角第n行的所有元素。因为n值不大,我们就可以直接通过一个数的值等于它肩膀两个数的值之和这个关系,不断一行一行的推出第n行的所有元素。

接着让每个长度为n的序列与该行对应元素相乘求和并与目标值比较,若相等,则打印序列并终止递归,否则继续搜索。到这里,经过优化后的算法效率显著提高了,将该思路的算法提交能拿90分,已经非常不错了。

还差10分,这10分差就差在没有剪枝。我们穷举序列不应该让长度为n的序列和杨辉三角相乘求和的结果与目标值s比较。而是应该在它生成的过程中就要与目标值s相比了,如果生成过程中的长度小于n的序列与杨辉三角相乘求和都已经大于目标值,那么完整序列必定大于目标值,可以提前终止递归。

代码

深度优先搜索就是按字典序由低到高的顺序开始试错寻找,当找到第一个符合条件的序列,即可直接返回,因为这个序列必定是字典序最小的序列。

# 杨辉三角
def triangle():# 存储杨辉三角的每行内容lines = [[1], [1, 1]]if n <= 2:# 当n小于等于2时,直接返回对应行,因为下标从0开始,所以是n-1return lines[n-1]# 从第三行开始遍历,因为已经有两个现成的,所以可以少遍历两行,故n-2for i in range(n - 2):temp = []# 遍历lines的最后一行以求取下一行的元素for j in range(len(lines[-1]) - 1):# 一个数的值等于它肩膀两个数的值之和val = lines[-1][j] + lines[-1][j + 1]temp.append(val)# 然后将特殊情况的两个1放进行里面lines.append([1] + temp + [1])# 返回杨辉三角最后一行,该行元素长度与序列元素长度相等return lines[-1]# 深度优先搜索  temp保存着生成的序列  cnt表示生成的序列元素与杨辉三角对应元素相乘之和  ind表示最后一个序列的下标
def search(temp, cnt, ind):# 不满足条件提前终止条件,实现剪枝if cnt > s:return Falseif len(temp) == n:# 当长度为n且cnt与目标值相等时,打印该序列所有元素if cnt == s:for i in temp:print(i, end=" ")# 已找到元素返回True,不用继续递归搜索return True# 如果不相符则返回False继续寻找return False# 遍历基序列,i表示索引,j表示对应索引下的值for i, j in enumerate(nums):# 如果该数字已使用,也就是生成的序列中已存在该数字,则不执行下面语句# 如果没有使用该数字,则运行下面程序if not used[i]:# 将未使用的数字标记为已使用used[i] = True# 将该数字加入到生成序列中temp.append(j)# 计算生成序列这个位置的值与杨辉三角对应位置的值乘积之和val = temp[ind] * yanghui[ind]# 将其加入到总和中cnt += val# 移动到下一个元素位置ind += 1# 继续回溯添加数字到生成数列中,如果已找到符合条件的序列直接返回Ture结束本次递归if search(temp, cnt, ind):return True# 状态重置,这是深度优先搜索的一个特点,如果没有找到符合条件的序列,就要取消选择最后选择的数字以选取其他数字used[i] = Falsetemp.pop()cnt -= valind -= 1n, s = map(int, input().split())
# nums是所有序列的根基,包含着序列中出现的所有元素
nums = [i for i in range(1, n + 1)]
# used为标记数组,标记数字是否使用过,used数组配合nums数组一起使用,用来标记第1~第n个数字是否使用过
used = [False for i in range(n)]
# 调用杨辉三角函数,获取最后一行所有元素
yanghui = triangle()
# 开始进行深度优先搜索
search([], 0, 0)

蓝桥杯 ALGO-1005 数字游戏 DFS记忆化搜索+剪枝+杨辉三角 python相关推荐

  1. 蓝桥杯 乘积最大(区间dp+记忆化搜索)

    问题描述 今年是国际数学联盟确定的"2000--世界数学年",又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一 ...

  2. dfs记忆化搜索(带限制的选择问题) 讲解:LeetCode打家劫舍||| / 蓝桥 地宫取宝/蓝桥 k进制数//剪格子//方格分割

    记忆化递归的必要性: 普通的递归可能会重复求解某一值,类似斐波那契数列.同样的子问题可能会被求解多次,这样就会很慢很慢很慢 解决方法:我们把历史求解(子问题)记录下来,如果下次需要求解子问题,那么直接 ...

  3. UVA10285 Longest Run on a Snowboard【DFS+记忆化搜索】

    Michael likes snowboarding. That's not very surprising, since snowboarding is really great. The bad ...

  4. ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 【bfs + 记忆化搜索 + 剪枝】 AC 代码

    ACM 北京区域赛 bfs+剪枝+ms 第一个一遍过的题目,基本没有看题解 记忆搜索当中,注意初始化成一个特殊值:而在访问之后,每个点就会有一个不同于INF(或者 -1等特殊标记)的值 先到先得,适者 ...

  5. 蓝桥杯 地宫取宝【第五届】【省赛】【C组】C++ dfs 记忆化搜索

    资源限制 时间限制:1.0s   内存限制:256.0MB X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被 ...

  6. 8636 跳格子(dfs+记忆化搜索)

    8636 跳格子 该题有题解 时间限制:2457MS  内存限制:1000K 提交次数:139 通过次数:46 题型: 编程题   语言: G++;GCC Description 地上有一个n*m 的 ...

  7. POJ1088 Bailian1088 滑雪【DFS+记忆化搜索】

    滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 114685 Accepted: 43807 Description Mic ...

  8. DFS——记忆化搜索——动态规划

    以洛谷P1802  5倍经验日 为例 https://www.luogu.org/problem/show?pid=1802 题目背景 现在乐斗有活动了!每打一个人可以获得5倍经验!absi2011却 ...

  9. 牛客假日团队赛5 F 随机数 BZOJ 1662: [Usaco2006 Nov]Round Numbers 圆环数 (dfs记忆化搜索的数位DP)...

    链接:https://ac.nowcoder.com/acm/contest/984/F 来源:牛客网 随机数 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言6 ...

最新文章

  1. 2、求100以内的素数之和。(20分)
  2. Oracle 11g Data Guard 使用duplicate from active database 创建 standby database
  3. Overview-ISA-2004-SP3
  4. java 找不到方法,已经定义的方法找不到
  5. linux基础知识——exec函数
  6. Spring Boot笔记-JPA中自定义@Query分页查询
  7. 宁德时代811电芯初现真容 搭配宝马X1混动汽车能量密度提升近6成
  8. Web前端程序员必备 前端面试题汇总(1)
  9. stm32 某个io引脚不能拉高_【stm32f407】IO引脚复用和映射
  10. SAS详细的下载与安装流程
  11. 台式计算机序列号怎么查,台式机如何查看序列号
  12. linux 的 绘画软件,Drawing Linux(简单画图工具)
  13. 阅读《吴军·硅谷来信》一年的回顾与思考
  14. c语言中十六进制可以直接和十进制运算吗,C语言 · 十六进制转十进制
  15. Android 音乐播放器
  16. 骑行运动耳机哪个好,五款最适合在骑行中佩戴的耳机分享
  17. DrawIO怎么画出卡通效果的?
  18. C#扫雷外挂辅助工具
  19. 无迹卡尔曼滤波UKF—目标跟踪中的应用(仿真部分)
  20. DTV下的AD Switch和Hearing Impaired功能介绍

热门文章

  1. 【NLP】地理信息系统原理与方法(第4版) 思维导图
  2. UVALive - 3510 Pixel Shuffle (群论)
  3. EntityFrameworkCore2.1的安装使用和其中遇到的那些坑
  4. P3391 文艺平衡树(Splay区间翻转)
  5. Mari 绘制高清脸部皮肤贴图
  6. z370主板参数_不再需要考虑Z370主板 平民级300系列即将上市
  7. z370对应的服务器芯片,Z370芯片组为何仅支持第八代酷睿处理器?供电针脚不一样!...
  8. python 一行代码去掉emoji表情符号
  9. 男生脸型测试比较好的软件,怎样测自己的脸型,男生脸型分类图
  10. double类型保留小数点后两位的几种方法