zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》0x28IDA* POJ3460Booksort

    题目链接:http://poj.org/problem?id=3460

    题目给定一个乱序序列,长度为n,其中的数是1-n,操作是将其中一段插入任何一个位置,问最少需要多少次操作能够使得序列有序,超过四次直接输出5ormore

    由于每个结点的分支数量达到了560,所以四层直接搜索时间复杂度很高,考虑IDA*,设置层数限制,并且使用未来估计,也就是最少需要的步数,如果最少需要的步数加上当前已经使用的步数

    已经大于固定的步数的话及时回溯。注意,就算当前步数加上估计步数小于等于规定的步数也不一定能搜索到最终状态,所以在搜索失败之后返回一个return false

    每一层中都需要单独保存这一层中用于扩展的状态,回溯时返回原状态并且转入下一个分支。

    本次也学到了一个技术,s/t上取整等于(s+t-1)/t下取整。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn = 20;
    int q[maxn];
    int n;
    int f(){//计算有最少的期望操作数 
        int tot=0;
        for(int i=0;i+1<n;i++)
        {
            if(q[i]+1!=q[i+1])tot++;
        }
        return (tot+2)/3;//tot/3上取整 
    } 
    bool check(){
        for(int i=0;i<n;i++)
            if(q[i]!=i+1)return false;
        return true;
    }
    bool dfs(int depth,int max_depth){
        if(depth+f() > max_depth)return false;//当前步数加上预估的最小步数大于指定最大步数
         if(check())return true;//成功搜索到目标状态
        
        int w[maxn];//每一层中单独记录原状态 
        //搜索每一个分支
        for(int len=1;len<=n;len++)//枚举长度 
            for(int l=0;l+len-1<n;l++){//枚举左端点 
                int r=l+len-1;
                for(int k=r+1;k<n;k++){    //枚举插入位置 ,向前插入与向后插入是重复的,只选向后的 
                    memcpy(w,q,sizeof(q));
                    //双指针扫描填数 
                    int x,y;
                    //将后面一段向前拼接 
                    for(x=r+1,y=l;x<=k;x++,y++)q[y]=w[x];
                    //前面一段向后拼接继续从y的位置开始 
                    for(x=l;x<=r;x++,y++)q[y]=w[x];
                    if(dfs(depth+1,max_depth)) return true;
                    memcpy(q,w,sizeof(w));
                }
            }
        return false;         
    } 
    int main(){
        int T;
        cin>>T;
        while(T--){
            scanf("%d",&n);
            for(int i=0;i<n;i++)scanf("%d",&q[i]);
            //操作步数 
            int depth=0;
            while(depth<5 && !dfs(0,depth))depth++;
            
            if(depth>=5)puts("5 or more");
            else printf("%d
    ",depth);
        }    
    } 
  • 相关阅读:
    [读书笔记]-技术学习-微服务架构与实践
    [文章转载]-Java后端,应该日常翻看的中文技术网站 -江南白衣
    [文章转载]-我的Java后端书架-江南白衣
    正则表达式有多强大一看便知!
    微信小程序支付功能完整流程
    判断字符串是否合法(1)
    ES6新增常用方法
    JS求一个字符串在另一个字符串中出现的次数
    根据对象的某个属性排序
    数组去除重复值的四种超简便方法
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13175239.html
Copyright © 2011-2022 走看看