AcWing 180. 排书

原题链接

打死本蒟蒻也想不到的估价函数

考察:IDA*

       知道初态和终态,明显可以用双向搜索.时间复杂度是O(15*15*15)5/2 计算出来是>1e9,但实际底数没有15*15*15那么大.第一个是枚举长度,第二个枚举左端点,第三个枚举要放的位置.可能可以压线过.这里主要讲IDA*解法,代码跑的时间是141ms

思路:

        IDA*算法是A*算法与迭代加深的结合.这里明显可以用迭代加深,难点主要在估价函数怎么想.

       终态的每个数比后一个数<1,我们每次将区间挪动,都可以改变3个位置的相邻数关系.可以计算初态相邻数关系不是终态关系的数量,那么估价函数的步数就是(tot+2)/3.

       即使只改变2个元素的关系也没关系,上取整使得预估函数返回1而并非0(所以一定不能用下取整)

       还有一个较难的是移动数组位置,我们需要备份数组.先将[r+1,k]的元素往前挪,再将[l,r]区间的元素赋值到目标位置.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int N = 16;
 6 int a[N],n,depth,b[5][N];
 7 int h()
 8 {
 9     int res = 0;
10     for(int i=1;i<n;i++)
11       if(a[i+1]-a[i]!=1) res++;
12     return (res+2)/3;
13 }
14 bool dfs(int step)
15 {
16     int val = h();
17     if(step+val>depth) return 0;
18     if(!val) return 1;
19     for(int len=1;len<=n;len++)
20       for(int l=1;l+len-1<n;l++)
21       {
22           int r = l+len-1;
23           for(int k=r;k<=n;k++)
24           {
25               memcpy(b[step],a,sizeof a);
26               int j = l;
27               for(int i=r+1;i<=k;i++,j++) a[j] = a[i]; 
28               for(int i=l;i<=r;i++,j++) a[j] = b[step][i];
29               if(dfs(step+1)) return 1;
30               memcpy(a,b[step],sizeof a);
31           }
32       }
33     return 0;
34 }
35 int main()
36 {
37     int T;
38     scanf("%d",&T);
39     while(T--)
40     {
41         scanf("%d",&n);
42         depth = 0;
43         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
44         while(depth<5&&!dfs(0)) depth++;
45         if(depth>=5) puts("5 or more");
46         else printf("%d\n",depth);
47     }
48     return 0;
49 }

 

posted @ 2021-04-19 22:14  acmloser  阅读(51)  评论(0编辑  收藏  举报