ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AcWing - 排书

2021-07-22 23:33:49  阅读:200  来源: 互联网

标签:cnt int 位置 dfs dep 排书 转移 AcWing


原题:

180. 排书 - AcWing题库

题意:

给你n个数的任意排列,现在要你通过从中选出一段,然后插入某个位置的操作将这n个数按顺序依次排列,同时操作次数最少。

分析:

普通的dfs肯定会超时间复杂度,所以要用IDA*,也就是迭代加深+估价函数。

代码有三个函数,f()表示估价函数。因为一次移动最多可以改变三个位置的后继,所以遍历当前排列,记录不满足a[i]=a[i-1]+1的位置个数cnt。最优的情况无非就是每次移动都正好使位置点的后继满足顺序,即只需要(cnt/3)上取整次操作。

check()是用来检查当前状态是否满足顺序。

由于用到迭代加深,dfs()中的dep是用来记录深度限制的。在这里主要想模拟一下区间移动的过程,虽然可能不难理解,但是图解会清晰一些。当前要对t[dep]与a数组进行交换,a记录的是转移后的结果,其中L、R表示需要转移的区间左右端点,len表示之间的长度,k(代码中的loc)表示的是需要插入的位置。

  1. 首先,因为两个数组一开始都是一样的,把t[dep]复制给a。

  1. 转移[L,R]后,[R+1,k]前移,因此直接转移[R+1,k]至L处。

  1. 转移[L,R]到k位置后,其他位置不变,转移完成。

题解:

#include <bits/stdc++.h>
using namespace std;
const int N=20;
int a[N],t[5][N];
int n;

int f()
{
    int cnt=0;
    for(int i=2;i<=n;i++)
    {
        if(a[i]!=a[i-1]+1) cnt++;
    }
    return (cnt+2)/3;
}
bool check()
{
    for(int i=2;i<=n;i++)
    {
        if(a[i]!=a[i-1]+1) return false;
    }
    return true;
}
bool dfs(int step,int dep)//当前移动步数,深度限制
{
    if(step+f()>dep) return false;//超限制
    if(check()) return true;
    
    //枚举开始位置l、移动长度len、移动到的位置loc
    for(int l=1;l<=n;l++)
    {
        for(int len=1;len+l-1<=n;len++)
        {
            int r=l+len-1;
            for(int loc=r+1;loc<=n;loc++)
            {
                //为什么t要开二维呢?因为需要往下递归然后回溯
                //不能覆盖之前深度的数组
                memcpy(t[step],a,sizeof a);
                //转移数组,更新状态
                int x,y;//x表示新数组中的位置,y表示原始数组中的位置
                for(x=r+1,y=l;x<=loc;x++,y++)
                {
                    a[y]=t[step][x];
                }
                for(x=l;x<=r;x++,y++)
                {
                    a[y]=t[step][x];
                }
                if(dfs(step+1,dep)) return true;
                memcpy(a,t[step],sizeof a);
            }
        }
    }
    
    return false;
}

int main()
{
    int T;
    cin>>T;
    
    while(T--)
    {
        cin>>n;
        
        for(int i=1;i<=n;i++) cin>>a[i];
        
        int dep=0;
        while(!dfs(0,dep)&&dep<5)
        {
            dep++;
        }
        if(dep>=5) cout<<"5 or more"<<endl;
        else cout<<dep<<endl;
    }
}

以上代码参考yxc老师的部分代码,yxcyyds!

(仅代表个人思考。如有错误,欢迎礼貌指正。如有疑问,欢迎友好交流。鄙人愚笨,敬请原谅。)

标签:cnt,int,位置,dfs,dep,排书,转移,AcWing
来源: https://www.cnblogs.com/atomsh/p/15046926.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有