UVa 11212 Editing a Book 编辑书稿 IDA* Iterative Deepening A Star 迭代加深搜剪枝

本文主要是介绍UVa 11212 Editing a Book 编辑书稿 IDA* Iterative Deepening A Star 迭代加深搜剪枝,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:Editing a Book
题目描述:

给定 n n n个( 1 < n < 10 ) 1<n<10) 1<n<10)数字,数字分别是 1 , 2 , 3 , . . . , n 1, 2, 3, ...,n 1,2,3,...,n,但是顺序是打乱的,你可以选择一个索引区间的数字进行剪切操作。问最少进行多少次剪切可以让这 n n n个数字变成升序。
例如 [ 1 , 2 , 4 , 3 ] [1, 2, 4, 3] [1,2,4,3]你可以选择剪切 3 3 3然后在 4 4 4的前面进行粘贴操作,那么该操作算一次剪切操作序列变得升序。

题解:

对于一个含有 n n n个数字的序列,要想让他变为升序,最多只需要进行 n n n次剪切操作一定能让序列升序(即每次都选择未剪切过的最大的数字剪切到开头,最多进行 n n n次操作,该序列一定变为有序)。那么我们可以依次枚举 [ 0 − n ] [0-n] [0n]表示可能的答案,每次进行暴力搜索,如果某一次枚举的时候搜索成功,那么此时枚举的次数就是最小的操作次数。这就是 I D ID ID算法( I t e r a t i v e D e e p e n i n g Iterative Deepening IterativeDeepening迭代深搜)。因为直接搜索的话,我们每次需要枚举区间以及移动的位置,那么复杂度会达到 ( n 3 ) d e p t h (n ^3)^{depth} (n3)depth带入最大值 9 9 9的话算出来的值接近 6 × 1 0 25 6\times 10^{25} 6×1025很明显会超时。
那么我们需要使用剪枝,如何进行剪枝呢?由于数字都是 1 − n 1-n 1n的,那么我们可以记录每个数字的后一个数字不正确的个数即计算有多少个 i i i满足: a [ i ] + 1 ] ≠ a [ i + 1 ] a[i] + 1] \ne a[i +1] a[i]+1]=a[i+1],我们将这个数字记为 c n t cnt cnt,我们可以发现我们每一次剪切操作最多让 c n t cnt cnt减少 3 3 3。从下图我们可以看到如果我们进行一次剪切(下图中是把part c移到到part b的前面),后一个数字发生变化的位置有:a的最后一个元素,c的最后一个元素, b的最后一个元素。 也就是说在这种情况想最多只有三个数字的后一个元素会发生改变,当然其他情况也是可以同理推出来的。所以每一次剪切操作最多能够让 c n t cnt cnt减少 3 3 3,如果剩余的剪切操作在最优的情况下不能让 c n t cnt cnt小于 0 0 0,那么此时就应该停止搜索即: ( m a x D e p t h − n o w D e p t h ) ∗ 3 < c n t (maxDepth - nowDepth) * 3 < cnt (maxDepthnowDepth)3<cnt。这也就是 A s t a r A\ star A star算法的思想,三部分合起来就叫做 I D A ∗ IDA* IDA
在这里插入图片描述
实际上仅仅有上面的剪枝策略还是容易发生超时。而此时需要利用另外一种“贪心”策略:连续的升序区间不应该被执行剪切操作,也就是说对于一个序列里面类似于 [ 2 , 3 , 4 , 5 ] [2, 3, 4, 5] [2,3,4,5]的序列只能作为整体操作,而不应该只剪切其中的一部分。这似乎是显然的。

代码:

#include <bits/stdc++.h>using namespace std;int n, caseID = 1;
vector<int> number;int getCnt()
{int cnt = 0;for (int i = 0; i < n - 1; i++) {if (number[i] + 1 != number[i + 1]) { cnt++; }}return cnt;
}bool dfs(int nowDepth, int maxDepth)
{int cnt = getCnt();if (nowDepth == maxDepth) { return cnt == 0; }if ((maxDepth - nowDepth) * 3 < cnt) { return false; }for (int l = 0; l < n; l++) {if (l - 1 >= 0 && number[l] - 1 == number[l - 1]) { continue; }for (int r = l; r < n; r++) { // 枚举需要移动的区间的左右端点if (r + 1 < n && number[r] + 1 == number[r + 1]) { continue; }for (int k = r + 2; k <= n; k++) { // 枚举将区间移动到k前面vector<int> temp(number);vector<int> worker;for (int i = 0; i <= k - 1; i++) { // [0, k-1]移动if (l <= i && i <= r) { continue; }worker.push_back(number[i]);}for (int i = l; i <= r; i++) { worker.push_back(number[i]); } // [l, r]移动for (int i = k; i < n; i++) { worker.push_back(number[i]); } // 剩下部分移动number.swap(worker);if (dfs(nowDepth + 1, maxDepth)) { return true; };number.swap(temp);}}}return false;
}int main()
{ios::sync_with_stdio(false);while(cin >> n && n != 0) {number.resize(n);for (int i = 0; i < n; i++) { cin >> number[i]; }for (int maxDepth = 0; ; maxDepth++) {if (dfs(0, maxDepth)) {cout << "Case " << caseID << ": " << maxDepth << endl;caseID++;break;}}}return 0;
}

这篇关于UVa 11212 Editing a Book 编辑书稿 IDA* Iterative Deepening A Star 迭代加深搜剪枝的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/270548

相关文章

使用Sublime Text 2编辑CoffeeScript

Sublime Text 2很好很强大,咱就用它来编辑Coffee代码吧。 安装Sublime Text 2过程就略过了。   CoffeeScript作者是推荐使用TextMate编辑CoffeeScript的。但是TextMate收费,并且对中文支持不好。如果你不在意这两个问题,那么强烈推荐你使用TextMate,并关注CoffeeScript作者的TextMate

UVA - 12206 Stammering Aliens (hash)

这题其实很容易想到2分长度,关键是2分后,怎么判断出现最多次的串是否》=m次了。这里需要用到hash来处理。 对于一个字符串   H[i] =H[i+1]*131+s[i]  ;其中 H[n]=0;那么对于一个长度为L的串 ,hanh[i,l]=H[i]-H[i+L]*x^L ; 这样记录每个字符串的hash值,然后再处理起来就比较简单了。 VIEW CODE #include<

在浏览器中打开预览sublime text当前所编辑文件的方法和快捷键设置

配置在Chrome,Firefox中打开 安装 SideBarEnhancements 然后通过ctrl + k, ctrl + b打开侧边栏,在侧边栏的文件中右击,找到 open width -> edit applications 然后在这里边设置firefox打开的方式。 application : 路径要修改为自己默认安装的路径。 [     {

STL迭代器的基础应用

STL迭代器的应用 迭代器的定义方法: 类型作用定义方式正向迭代器正序遍历STL容器容器类名::iterator 迭代器名常量正向迭代器以只读方式正序遍历STL容器容器类名::const_iterator 迭代器名反向迭代器逆序遍历STL容器容器类名::reverse_iterator 迭代器名常量反向迭代器以只读方式逆序遍历STL容器容器类名::const_reverse_iterato

递归 迭代 得到家谱树 子孙树

<?php $arr=array(array('id'=>'1','name'=>'吉林','parent'=>0),array('id'=>'2','name'=>'北京','parent'=>0),array('id'=>'3','name'=>'辽宁','parent'=>0),array('id'=>'4','name'=>'吉林市','parent'=>1),array('id'=>'5

java的单例集合迭代器

迭代器Iterator         根据之前的介绍我们知道,单例集合是由接口Collection定义的容器。Collection接口之下由定义了List接口和Set接口,其中List接口定义的容器的特征是有序可重复,而Set接口定义的容器的特征是无序不可重复的。         List接口定义的容器的底层是通过数组来实现的,它的每一个容器中的元素都具有属于自己的索引,因此可以定义重复的元

Adobe Acrobat 编辑器软件下载安装,Acrobat 轻松编辑和管理各种PDF文件

Adobe Acrobat,它凭借卓越的功能和丰富的工具,为用户提供了一个全面的解决方案,用于查看、创建、编辑和管理各种PDF文件。 作为一款专业的PDF阅读器,Adobe Acrobat能够轻松打开并展示各种格式的PDF文档,无论是文字、图片还是表格,都能以清晰、准确的方式呈现给用户。 同时,它还支持多种缩放和浏览模式,让用户能够根据自己的需求自由调整阅读界面,获得最佳的阅读体验。 在

文本框可编辑查看页面

<!DOCTYPE html><html><head><meta charset="utf-8" /><title>文本框可编辑查看页面</title><script type="text/javascript" src="js/jquery-1.7.2.min.js" ></script><style>.form_ul li{margin-top: 5px; font-size: 14px;l

linux vi编辑 整理

:w 保存文件但不退出vi :w file 将修改另外保存到file中,不退出vi :w! 强制保存,不推出vi :wq 保存文件并退出vi :wq! 强制保存文件,并退出vi q: 不保存文件,退出vi :q! 不保存文件,强制退出vi :e! 放弃所有修改,从上次保存文件开始再编辑