前言
1.路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条从初始状态到终止状态的最优路径,而不是像回溯法那样找到一个满足约束的解。
2.迭代加深搜索:从小到大枚举深度上限maxd,每次执行只考虑深度不超过maxd的结点。
提示:对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑使用迭代加深搜索。
一、排书
题目描述
给定n本书,编号为1-n。
在初始状态下,书是任意排列的。
在每一次操作中,可以抽取其中连续的一段,再把这段插入到其他某个位置。
我们的目标状态是把书按照1-n的顺序依次排列。
求最少需要多少次操作。
输入格式
第一行包含整数T,表示共有T组测试数据。
每组数据包含两行,第一行为整数n,表示书的数量。
第二行为n个整数,表示1-n的一种任意排列。
同行数之间用空格隔开。
输出格式
每组数据输出一个最少操作次数。
如果最少操作次数大于或等于5次,则输出”5 or more”。
每个结果占一行。
数据范围
1≤n≤15
输入样例:
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.典型状态空间搜索
题。
2.样例分析:5 4 3 2 1 -> 3 2 5 4 1 -> 3 4 1 2 5 -> 1 2 3 4 5
3.当移动连续k个数时,有n-k+1种选法,对每种选法,有n-k种放法。每个状态总共的操作个数为(15 * 14 + 14 * 13 + … + 2 * 1)/ 2 = 560.因此时间复杂度为5604,必然超时。我们用IDA算法来优化。
4.IDA*算法
核心:估价函数
必须小于等于真实值,并且越接近真实值越好—>判断在当前状态下,最少进行多少次操作,才能使序列有序。
因为每次移动最多会断开三个连接,再重新加入三个连接,因此最多会将3个连接修正,所以如果当前有 tot 个连接,那么最少需要 [tot/3]次操作。因此当前状态 s 的估价函数可以设计成 f(s)=[tot/3]
。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 15;
int n;
int q[N], w[5][N];
int f() //估价函数
{
int res = 0;
for (int i = 0; i + 1 < n; i ++ )
if (q[i + 1] != q[i] + 1)
res ++