11212 - Editing a Book(IDA*算法)

又一道迭代加深搜索,从小到大枚举上限 。   关键的剪枝部分是写出启发函数,这个比较难。。

不过每次剪切后,不正确的数字个数最多减三还是很好理解的,因为我们算不正确数字个数的方法是看当前数字+1是不是等于下一个数字 。 所以每次剪切最多只有3个数字的后继数字发生了改变。  那么 剪枝条件就显而易见了 。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 15;
int n,a[15],kase = 0,maxd;
bool is_sort() {
    for(int i=0;i<n-1;i++)
        if(a[i] >= a[i+1]) return false;
    return true;
}
int h() {
    int cnt = 0;
    for(int i=0;i<n-1;i++)
        if(a[i]+1 != a[i+1]) cnt++;
    if(a[n-1] != n) cnt++;
    return cnt;
}
bool dfs(int d,int maxd) {
    if(d*3 + h() > maxd*3) return false;//剪枝
    if(d == maxd) {
        if(is_sort()) return true;
        return false;
    }
    int b[maxn],olda[maxn];
    memcpy(olda,a,sizeof(a));//复制以方便恢复

    for(int i=0;i<n;i++) {
        for(int j=i;j<n;j++) { //枚举要剪切的连续区间的端点[i,j]
            int cnt = 0;
            for(int k=0;k<n;k++)
                if(k < i || k > j) b[cnt++] = a[k]; //将未剪切的部分拼接
            for(int k=0;k<cnt;k++) { //枚举将要插入到k之前
                int cnt2 = 0;
                for(int p=0;p<k;p++) a[cnt2++] = b[p]; //插入点前的部分
                for(int p=i;p<=j;p++) a[cnt2++] = olda[p]; //插入的(被剪切的部分)
                for(int p=k;p<cnt;p++) a[cnt2++] = b[p];//插入点之后的
                if(dfs(d+1,maxd)) return true;
                memcpy(a,olda,sizeof(a));//复制回来
            }
        }
    }
    return false;
}
int main() {
    while(~scanf("%d",&n)&&n) {
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        for(maxd = 0; maxd < 8 ; ++maxd) {
            if(dfs(0,maxd)) break;
        }
        printf("Case %d: %d\n",++kase,maxd);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 20:25:26

11212 - Editing a Book(IDA*算法)的相关文章

UVa 11212 Editing a Book (IDA* &amp;&amp; 状态空间搜索)

题意:你有一篇n(2≤n≤9)个自然段组成的文章,希望将它们排列成1,2,-,n.可以用Ctrl+X(剪切)和Ctrl+V(粘贴)快捷键来完成任务.每次可以剪切一段连续的自然段,粘贴时按照顺序粘贴.注意,剪贴板只有一个,所以不能连续剪切两次,只能剪切和粘贴交替.例如,为了将{2,4,1,5,3,6}变为升序,可以剪切1将其放到2前,然后剪切3将其放到4前.再如,排列{3,4,5,1,2},只需一次剪切和一次粘贴即可--将{3,4,5}放在{1,2}后,或者将{1,2}放在{3,4,5}前. 分析

uva 11212 - Editing a Book(迭代加深搜索 IDA*) 迭代加深搜索

迭代加深搜索 自己看的时候第一遍更本就看不懂..是很水,但智商捉急也是没有办法的事情. 好在有几个同学已经是做过了这道题并且对迭代加深搜索的思路有了一定的了解,所以在某些不理解的地方询问了一下他们的见解, 真的是很有帮助,也许自己想要想很久才能想明白,还会很痛苦,稍微问一下别人的想法,点上一个方向,剩下的自己就能想得明白了. 迭代加深. 把answer(需要的步数或其他)在主函数里面从零往上递加,此之谓 "层数",亦可谓之"深度".用书上的话就是: 从小到大枚举深度

UVA 11212 Editing a Book [迭代加深搜索IDA*]

11212 Editing a Book You have n equal-length paragraphs numbered 1 to n. Now you want to arrange them in the order of 1, 2, . . . , n. With the help of a clipboard, you can easily do this: Ctrl-X (cut) and Ctrl-V (paste) several times. You cannot cut

[2016-02-27][UVA][11212][Editing a Book]

[2016-02-27][UVA][11212][Editing a Book] 时间:2016-02-26 19:38:44 星期五 题目编号:UVA 11212 题目大意:给定长度为n(值为1~n)的序列,求把该序列 复制/粘贴 成1~n 的排列最少步数 分析: 状态空间搜索,但是每次状态转移的方式有多种,可能会T, 发现,最多 操作 的次数:n~1的序列,每次操作 长度为1的连续段,那么需要 n-1 次操作 可以用IDA*算法 剪枝,每次操作之后,每个数字的后继数字不正确的数目h,最多减少

UVA 11212 Editing a Book

题意: 有一篇由n个自然段组成的文章.希望将他们排成递增序列.只能剪贴和粘贴交替进行,剪贴时可以剪贴一段连续的自然段. 分析: 用IDA*算法求解.当3*d+h>maxd时剪枝. 代码: #include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;string goal;int n;bool dfs(int d,int max

1343 - The Rotation Game (IDA*算法)

紫书上给的是状态空间搜索,其实本题也可以用IDA*算法,因为其符合IDA*的特点 : 求最小迭代次数 . 根据旋转的规律,我们可以用几个数组来储存向各个方向旋转时改变哪些量,用来维护旋转这个操作 .另外就是估价函数:当前出现在中间八个格子中次数最多的数字设为t ,那么剩下的迭代次数就是8 - t  , 如果它加上已经迭代的次数d > maxd ,则应当剪枝 . 另外想到了一个估算回溯法的时间复杂度的好办法 : 一般在每一层进入下一层的可能数设为t , 最大迭代次数设为 d  , 那么时间复杂度为

hdu-4127 Flood-it!(IDA*算法)

今天做的福州赛区区域赛的题目重现,一整场都在抠这道题仍然无法AC,时间卡的很紧,不过其实也是自己的搜索学的实在太差,紫书上刷的最少的就是第七章的题 . 我一开始就看出了这道题需要IDA*算法,但是昨天才看的还没能深入理解,通过赛后补这道题,感觉整体思路有了一个新的突破 . IDA*算法就是迭代加深搜索和A*算法的结合,迭代加深搜索非常简单,就是从小到大枚举深度上限,适合求解深度未知的或者像该题一样需要求最小迭代次数的题目 . A*算法的精髓是写一个估价函数, 如何写呢? 其实就是一个剪枝,通过计

12558 - Egyptian Fractions (HARD version)(IDA*算法)

IDA*算法,迭代加深搜索和A*算法的结合 . 迭代加深搜索适用于那些没有明显深度上限的题目,将深度从小到大枚举,直到找到最优解 ,减小了深搜的盲目性 . A*算法需要一个乐观估价函数,在这个函数里寻找一个代价最小的点去搜索,所以时间复杂度都浪费在这个上面了 . 代码如下: #include<bits/stdc++.h> using namespace std; typedef long long ll; int T,kase=0; ll v[10000+10],ans[10000+10],a

【UVa】11212 Editing a Book(IDA*)

题目 题目 ? ? 分析 get一下IDA*的技巧,感觉总体来说不难,主要是剪枝比较难想. 这是lrj的代码,比较通俗易懂,关键就是选定一个区间再取出来,插入到一个位置,接下来转移到这个状态. ? ? 代码 #include <bits/stdc++.h> using namespace std; const int maxn=10; int n,a[maxn]; bool is_sorted() { for(int i=0;i<n-1;i++) if(a[i]>=a[i+1])