Uva11212 Editing a Book【IDA*】【例题7-10】

题目:Editing a Book

题意:给n个数字,最少需要几次排成递增序列,可片段的插入。

思路:

(1)枚举:因为不确定最少几次排好,所以枚举步数:最多需8步,n<=9 .

(2)搜索:每次枚举当前要达到的深度(步数),然后进行dfs搜索

         dfs:用俩层循环枚举剪切片段的起始点和终止点,然后在剪切剩下的片段中将剪切片段依次在每一个位置的前面插入组成一个新序列后进行判断。

(3)判断: 每次组成一个新序列后进行判断是否为递增,是直接返回true。结束枚举。

(4)剪枝:求出每次的新序列的后继不正确的数字个数h可以证明每次剪切时h最多减少3 例如:序列 9 8 7 6 5 4 3 2 1    剪切部分:765      将 765 插入到 3与2之间,则 8 连接的是4 ,3连接的是7 ,2连接的是5 ,出现3处。

所以:3d+h>3maxd时可以剪枝,其中d为当前深度,maxd为深度限制

IDA* : 迭代深度搜索 + 超出范围的剪枝

参考:某大神链接

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10;
int n,a[maxn];
bool is_sort(){//判断是否是递增序列
    for(int i=0;i<n;i++) if(a[i] != 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(3*d + h() > 3*maxd) return false;//剪枝
    if(is_sort()) return true;
    int original[maxn],part[maxn];
    memcpy(original,a,sizeof(a));//保留原序列
    for(int i=0;i<n;i++){//枚举起始点
        for(int j=i;j<n;j++){//枚举终止点
            int cnt_part = 1;//这里必须从1开始记录,因为下面插入的时候是从k前插入
            for(int k=0;k<n;k++) if(k < i || k > j) part[cnt_part++] = original[k];//将剪切判断除外的数字保留
            //将剪切部分依次插入原序列的每一个位置上,放入a数组中!,在k前插入!
            for(int k=0;k<cnt_part;k++){
                int cnt_whole = 0;
                for(int p=1;p<=k;p++) a[cnt_whole++] = part[p];//起始点的部分
                for(int p=i;p<=j;p++) a[cnt_whole++] = original[p];//将剪切部分插入
                for(int p=k+1;p<cnt_part;p++) a[cnt_whole++] = part[p];//终止点的部分
                if(dfs(d+1,maxd)) return true;
            }
        }
    }
    return false;
}
int solve(){
    if(is_sort()) return 0;
    for(int maxd=1;maxd<9;maxd++){//枚举深度
        if(dfs(0,maxd)) return maxd;
    }
    return 5;
}
int main()
{
    int kcase = 0;
    while(scanf("%d",&n)!=EOF && n){
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        printf("Case %d: %d\n",++kcase,solve());
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值