每周一算法:迭代加深A*

题目链接

AcWing 180. 排书

题目描述

给定 n n n 本书,编号为 1 ∼ n 1\sim n 1n

在初始状态下,书是任意排列的。

在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。

我们的目标状态是把书按照 1 ∼ n 1\sim n 1n 的顺序依次排列。

求最少需要多少次操作。

输入格式

第一行包含整数 T T T,表示共有 T T T组测试数据。
每组数据包含两行,第一行为整数 n n n,表示书的数量。
第二行为 n n n个整数,表示 1 ∼ n 1\sim n 1n 的一种任意排列。

同行数之间用空格隔开。

输出格式

每组数据输出一个最少操作次数。

如果最少操作次数大于或等于 5 5 5次,则输出5 or more

每个结果占一行。

数据范围

1 ≤ n ≤ 15 1≤n≤15 1n15

输入样例

3
6
1 3 4 6 2 5
5
5 4 3 2 1
10
6 8 5 3 4 7 2 9 1 10

输出样例

2
3
5 or more

算法思想

根据题目描述,需要对 1 ∼ n 1\sim n 1n的一个排列,进行若干次操作,在每一次操作中,可以抽取序列中连续的一段,再把这段插入到其他某个位置。问最少经过几次操作,可以将序列变为按照 1 ∼ n 1\sim n 1n 的顺序依次排列。

先考虑每一次操作的决策数量:

  • 当从序列中抽取长度为 i i i的一段时,有 n − i + 1 n-i+1 ni+1种选择。例如:对于长度 n = 6 n=6 n=6的序列中,抽取长度为 i = 3 i=3 i=3的连续一段,有 4 4 4种选择,如下图所示
    在这里插入图片描述
  • 对于每种抽法,有 n − i n-i ni种放法,即将长度为 i i i的一段插入其它 n − i n-i ni个空中。例如:
    在这里插入图片描述

那么每一步状态数量为 ( n − i ) × ( n − i + 1 ) (n-i)\times(n-i+1) (ni)×(ni+1),但将某一段向前移动,等价于将跳过的那段向后移动,因此每种移动方式被计算了两次,还要除以 2 2 2。所以状态空间的大小为 ∑ i = 1 n ( n − i ) × ( n − i + 1 ) / 2 ≤ ( 15 × 14 + 14 × 13 + . . . + 2 × 1 ) / 2 = 560 \sum_{i=1}^n(n-i)\times(n-i+1)/2\le(15\times14+14\times13+...+2\times1)/2=560 i=1n(ni)×(ni+1)/2(15×14+14×13+...+2×1)/2=560

考虑在 4 4 4步内找到答案,最多有 56 0 4 560^4 5604个状态,暴力搜索会超时。可以使用双向广搜 或者迭代加深A*(IDA* )来优化。

迭代加深A*

在A*算法算法中,将估价函数与优先队列BFS结合,提高了搜索效率。那么把估价函数与迭代加深的DFS结合就是迭代加深 A* \text{A*} A* IDA* \text{IDA*} IDA*)。

迭代加深 A* \text{A*} A*要限定一个深度,在不超过该深度的前提下执行DFS,若找不到解,就扩大深度限制,重新进行搜索;除此之外,还要设计一个估价函数,估算从每个状态到目标状态需要的“步数”。与 A* \text{A*} A*算法一样,估价函数需要遵守“预计值不大于未来实际步数”的准则。

基本思想是以迭代加深DFS的搜索框架为基础,把原来简单的深度限制加强为:若当前深度+未来估计步数>深度限制,则立即从当前分支回溯

估价函数

IDA* \text{IDA*} IDA*的算法的关键在于设计估价函数,那么本题的估价函数如何设计?考虑对于目标状态,第 i i i本书后边应该是第 i + 1 i+1 i+1本书,那么认为 i + 1 i+1 i+1 i i i的正确后继。

对于任意状态,考虑整个排列中错误的后继总数,将其记为tot,可以发现每次操作至多更改 3 3 3本数的后继,例如,将 346 346 346移动到 2 2 2的后面, 1 、 2 、 6 1、2、6 126的后继被更改,如下图所示:将346移动到2的后面,126的后继被更改
也就是说,在最理想的情况下,每次操作都能把 3 3 3个错误后继全部该对,那么消除所有错误后继的操作次数也至少需要 ⌈ t o t 3 ⌉ \lceil\frac{tot}{3}\rceil 3tot次。

因此,可以把一个状态state的估价函数设计为 h ( s t a t e ) = ⌈ t o t 3 ⌉ h(state)=\lceil\frac{tot}{3}\rceil h(state)=3tot,其中tot表示在当前状态state下书的错误后继总数。

算法实现

基本思想是使用迭代加深的方法,从 1 ∼ 4 1\sim4 14依次限制搜索深度,然后从起始状态出发进行DFS。对于当前状态:

  • 如果若当前步数+未来估计步数>深度限制,则搜索结束返回无解。
  • 如果到达最终状态,搜索结束返回有解。
  • 枚举要抽连续的一段的左右位置 [ L , R ] [L, R] [L,R],以及插入位置 i i i,将 [ L , R ] [L, R] [L,R]这一段插入到 i i i位置后
    • 继续搜索下一阶段的状态

代码实现

#include <bits/stdc++.h>
using namespace std;
const int N = 20;
int n, q[N], b[5][N]; //备份数组
int h() //估价函数
{int tot = 0; //统计错误后继总数for(int i = 0; i + 1 < n; i ++)if(q[i] + 1 != q[i + 1]) tot ++;return (tot + 2) / 3; //总数÷3向上取整
}
bool check()
{for(int i = 0; i < n; i ++)if(q[i] != i + 1) return false;return true;
}
//当前步数k,限制深度depth
bool dfs(int k, int depth)
{if(k + h() > depth) return false; //当前步数+估计步数超过限制if(check()) return true;//枚举抽取的左右两端和插入位置for(int L = 0; L < n; L ++)for(int R = L; R < n; R ++)for(int i = R + 1; i < n; i ++) //注意只需要枚举后面的插入位置即可{memcpy(b[k], q, sizeof q); //备份,方便恢复现场int x, y;//将[R+1,i]位置上的数向前移动for(x = R + 1, y = L; x <= i; x ++, y ++) q[y] = b[k][x];//将[L,R]位置上的数,向后移动for(x = L; x <= R; x ++, y ++) q[y] = b[k][x];if(dfs(k + 1, depth)) return true;memcpy(q, b[k], sizeof q); //备份,方便恢复现场}return false;
}
int main()
{int T;cin >> T;while(T --){cin >> n;for(int i = 0; i < n; i ++) cin >> q[i];int depth = 0;while(depth < 5 && !dfs(0, depth)) depth ++;if(depth >= 5) puts("5 or more");else cout << depth << '\n';}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/766042.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能风扇的新篇章:唯创知音WTK6900G语音识别芯片引领行业革新

随着科技浪潮的推进&#xff0c;智能化技术逐渐渗透到生活的每一个角落&#xff0c;家电领域尤为明显。风扇&#xff0c;这一夏日清凉神器&#xff0c;也通过智能化改造&#xff0c;焕发出前所未有的光彩。其中&#xff0c;智能语音控制功能的加入&#xff0c;为风扇的使用带来…

Linux基础语法学习外加练习题,训练一、创建文件相关练习题二、文件管理相关练习题三、vim编辑器的练习四、用户管理相关操作

练习题答案请点击链接查看&#xff1a;​​​​​​​Linux基础语法练习题&#xff0c;配有答案&#xff0c;题目内容如下&#xff1a;一、创建文件相关练习题二、文件管理相关练习题三、vim编辑器的练习四、用户管理相关操作-CSDN博客 一、常用命令 1 、 linux 命令特点 1. …

服务器软件express搭建web服务器

文章目录 1.express 是什么2.路由2.1&#xff08;参数一&#xff09;读取用户的请求&#xff08;request&#xff09;2.2&#xff08;参数二&#xff09;给用户响应&#xff08;response&#xff09;2.3&#xff08;参数三&#xff09;next()函数&#xff08;传递请求到下一个处…

科研学习|论文解读——真实与综合:研究设置和任务配置对搜索行为的影响(JASIST,2021)

原文题目 Authentic versus synthetic: An investigation of the influences of study settings and task configurations on search behaviors 摘要 在信息检索和检索研究中,研究者经常收集用户行为数据来预测任务特征,为用户提供个性化信息提供参考。数据采集方法可能会直接…

[AIGC] 主流工作流引擎对比与适用场景介绍

主流工作流引擎对比与适用场景介绍 工作流引擎在业务流程管理中扮演着重要的角色&#xff0c;它可以帮助组织将复杂的工作流程自动化&#xff0c;降低错误率&#xff0c;提高工作效率。目前市面上有许多优秀的工作流引擎&#xff0c;各自都有着独特的优点和适用的场景。本文将介…

动态规划15 | ● 392.判断子序列 ● *115.不同的子序列

392.判断子序列 https://programmercarl.com/0392.%E5%88%A4%E6%96%AD%E5%AD%90%E5%BA%8F%E5%88%97.html 考点 子序列问题 我的思路 dp[i][j]的含义是&#xff0c;两个序列分别取到下标为i和j的时候&#xff0c;他们是否满足前者是后者的子序列&#xff0c;满足为True&#x…

涨知识啦!如何使用3dMax和Vray渲染三维室内平面图效果图?

使用3dMax渲染三维室内平面图教程 在建筑和室内设计领域,3D平面效果图在建筑师或设计师与其客户之间更好地沟通方面发挥着重要作用。并不是每个人都能“阅读”建筑二维平面图及其所有技术元素,因此将该平面图转换为更易于理解的布局是很重要的。一个简单的方法是只使用2D图形…

第二十二章 TypeScript weakMap,weakSet,set,map

在es5的时候常用的Array object &#xff0c;在es6又新增了两个类型&#xff0c;Set和Map&#xff0c;类似于数组和对象。 1.set 集合是由一组无序且唯一(即不能重复)的项组成的&#xff0c;可以想象成集合是一个既没有重复元素&#xff0c;也没有顺序概念的数组 属性 size&…

flutter-elinux的基本介绍及安装调试

搜集到两个很有用的网站&#xff1a; 1、flutter-elinux的基本介绍&#xff1a;https://juejin.cn/post/7257285697383612453 2、flutter-elinux的安装调试等&#xff1a;https://github.com/sony/flutter-elinux/wiki 其中&#xff0c;在flutter-elinux设置环境变量时&#…

SSL加密:保护数据传输的安全盾牌

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

AcWing 1250. 格子游戏 (并查集,坐标变换)

记录此题的目的&#xff1a; 明确二维的坐标可以映射到一维&#xff1a;在x和y都是从0开始的前提下&#xff0c;假如图形列数为n&#xff0c;(x,y)映射到一维可以写成x * n y。并查集并不好存储二维数据&#xff0c;如果遇到二维数据可以将其映射到一维。 Alice和Bob玩了一个…

Rust 的 PhantomData

在 Rust 中&#xff0c;PhantomData 是一个零大小的标记类型&#xff0c;用于表示泛型参数的某种“幽灵”所有权或依赖性&#xff0c;而不实际持有该类型的数据。它在标准库中的 std::marker 模块下提供。 使用 PhantomData 的主要场景有&#xff1a; 占位以满足泛型约束&…

Prometheus+Grafana 监控Tongweb7(by lqw)

文章目录 1.准备工作2.Tongweb7部署3.Prometheus部署4.上传jar包并配置Tongweb75.Prometheus配置6.安装和配置Grafana 1.准备工作 本次参考&#xff1a;Prometheus监控Tongweb容器 1.使用虚拟机ip&#xff1a;192.168.10.51&#xff08;tongweb&#xff09;&#xff0c;192.1…

Linux源码包安装

目录 一、transmission源码包安装 二、 nginx源码包安装 一、transmission源码包安装 1、下载编译环境所需的软件包依赖 2、下载transmision源码包到用户主目录下 https://github.com/transmission/transmission/releases/download/4.0.5/transmission-4.0.5.tar.xz 3、解压…

【python】学习笔记04-函数

4.1 函数介绍 1. 函数是&#xff1a; 组织好的、可重复使用的、用来实现特定功能的代码段 2. 使用函数的好处是&#xff1a; • 将功能封装在函数内&#xff0c;可供随时随地重复利用 • 提高代码的复用性&#xff0c;减少重复代码&#xff0c;提高开发效率 4.2 函数的定义 …

MySQL内存表和临时表的区别

在MySQL中有三种虚拟表&#xff1a;临时表、内存表、视图。 一、内存表 表结构在磁盘&#xff0c;数据和索引保存在内存里面&#xff0c;MySQL服务重启数据丢失,但表结构依旧存。断开连接结构和数据依然存在参数控制&#xff1a;max_heap_table_size到达上限后报错不能包含TE…

【PHP】通过PHP安装数据库并使数据初始化

一、前言 有些CMS在部署的时候不用使用数据库工具&#xff0c;而是通过数据库安装页面就能完成数据库创建和数据填充&#xff0c;所以自己就想动手做一个这样的功能&#xff0c;这样在给别人安装系统的时候就不用再那么麻烦了&#xff0c;直接一键安装解决了。 二、效果图 输…

基于骨骼的动作识别的行动结构图卷积网络

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;基于骨骼的动作识别的行动结构图卷积网络1、研究背景2、方法提出3、关键结构3.1、A-links inference module (AIM)3.2、Structura…

【测试开发学习历程】MySQL分组查询与子查询 + MySQL表的联结操作

目录 1 MySQL分组查询与子查询 1.1 数据分组查询 1.2 过滤分组 1.3 分组结果排序 1.4 select语句中子句的执行顺序 1.5 子查询 2 MySQL表的联结操作 2.1 关系表 2.2 表联结 2.3 笛卡尔积 2.4 内部联结 2.5 外联结 2.6 自联结 2.7 组合查询 1 MySQL分组查询与子查询…

day16-环形链表

问题描述&#xff1a; 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0…