UVA11212 编辑书稿 Editing a Book (IDA*)

IDA*

portal

博大精深的算法,也就是所谓的迭代加深搜索,适用在dfs里,是一种通过深度上限和估价函数来限制搜索树从而剪枝的方法。

$ maxd $ $g(n)$ $h(n)$ 分别为我们指定的最大搜索深度,当前搜索深度,乐观估价函数。其中 $maxd$ 通过枚举得到,接下来通过本题讲讲乐观估价函数。

顾名思义,他是在最乐观的情况下进行的,他代表的是当前深度最乐观情况下还需要将搜索树加深几层,换句话说,就是至少再进行几次操作。对于本题我们可以这么来设计:

考虑 $a$ $b$ $c$ $d$ 四个相邻序列,假设我们剪切 $b$ 变为 $a$ $c$ $b$ $d$ 那么最好情况是什么?就是 $ac$ $cb$ $bd$ 之间相邻的数都合法了,那么最多一次我们可以使 $3$ 组合法,进而我们可以得出,对于数列中所有不合法的 $h$ 组数对,最理想情况下我们只需要 $h/3$ 次操作使他变成目标序列。那么不合法的就变成了 $h(n)/3 + g(n) > maxd$ 再变一下就是 $h(n) + g(n) * 3 > maxd$ 。这就是所谓的估价函数。

剩下的只需要按照他说的剪切就行了。

#include<cstdio>
#include<queue>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cctype>
#include<vector>
#include<string>
using namespace std;
const int N = 15;
int n,depth,flag;
int a[N];
inline int evaluate(){
    int res = 0;
    for(int i=1;i<=n;++i)if(a[i] != a[i-1] + 1)res++;
    return res;
}
inline void f(int to_start,int from_start,int end,int *p,int *q){
    for(int i=to_start,j=from_start;j<=end;++j,++i)p[i] = q[j];
} 
inline void IDA_star(int now_depth){
    int res = evaluate();
    if(now_depth * 3 + res > depth * 3)return;
    if(res == 0)return flag = 1,void();
    int b[N],c[N];
    memcpy(b,a,sizeof(b));
    for(int i=1;i<=n;++i){
        if(a[i] != a[i-1] + 1){//不合法 
            for(int j=i;j<=n;++j){//子段枚举 
                if(j < n && a[j+1] == a[j] + 1)continue;//合法 
                if(a[j+1] > a[j])continue;//合法 
                for(int k=i;k<=j;++k)c[k] = a[k];//存当前子序列 
                for(int k=j+1;k<=n;++k){//枚举粘贴的右节点 
                    if(k < n && a[k+1] == a[k] + 1)continue;//当前点与他后面的合法,不动 
                    f(i,j+1,k,a,a);//就是把当前j+1 ~ k这一段给我们的上面的子序列i~i+k-j,粘贴过来 
                    f(i+k-j,i,j,a,c);//子序列里的粘贴过去 
                    IDA_star(now_depth+1);
                    memcpy(a,b,sizeof(a));//回溯 
                    if(flag)return;
                }
            }
        }
    }
}
int main(){
    int cnt = 0;
    while(scanf("%d",&n) == 1 && n){
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;++i)scanf("%d",a+i);
        flag = 0;
        for(depth = 0;depth <= n;++depth){
            IDA_star(0);
            if(flag)break;
        }
        printf("Case %d: %d\n",++cnt,depth);
    }
}

 

posted @ 2022-03-17 15:44  Xu_brezza  阅读(55)  评论(0编辑  收藏  举报