P2534 [AHOI2012]铁盘整理

原题链接

考察:IDA*+离散化

这估价函数本蒟蒻完全没想到....

思路:

      最少操作次数,如果用bfs需要存储数组.考虑一波IDA*,无需存储数组只需要回溯.但是估价函数不好想.参考了大佬的题解,原来需要离散化....将不同的半径按大小映射为1~n之间的数字.目标就是让最终序列为1...n递增排序.可以发现,我们每操作一次,就改变操作区间右端点与非操作区间左端点的大小关系.我们可以发现最终序列a[i+1]-a[i] = 1.那么对于当前序列a[i+1]-a[i] != 1,res++.是否可行?

      答案是不可行.对于5 4 3 2 1.按上面的预估函数返回结果是4,实际操作数是1.那么延伸一下abs(a[i+1]-a[i])!=1,res++.是否可行.答案是可行,但我们需要将a[n+1]设置为n+1才行.否则5 4 3 2 1返回0.

      这样的预估函数为什么正确?对于a[l],a[l+1],如果它们之间的差不是1 or -1,那么就需要将前面的数换走,否则两者前后两者之差的绝对值不会改变.所以每一个不为-1 or 1的差,至少需要1次翻转.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 20;
 6 int r[N],n,b[N],deep;
 7 int h()
 8 {
 9     int res = 0;
10     for(int i=0;i<n;i++)
11       res+=(abs(r[i+1]-r[i])==1?0:1);
12     return res;
13 }
14 bool dfs(int depth,int pre)
15 {
16     int val = h();
17     if(val+depth>deep) return 0;
18     if(!val) return 1;
19     for(int i=2;i<=n;i++)
20     {
21         if(i==pre) continue;
22         reverse(r,r+i);
23         if(dfs(depth+1,i)) return 1;
24         reverse(r,r+i);
25     }
26     return 0;
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     for(int i=0;i<n;i++) scanf("%d",&r[i]);
32     memcpy(b,r,sizeof r);
33     sort(b,b+n);
34     for(int i=0;i<n;i++)
35        r[i] = lower_bound(b,b+n,r[i])-b+1;
36     r[n] = n+1;
37     while(!dfs(0,-1)) deep++;
38     printf("%d\n",deep);
39     return 0;
40 }

 

总结:

        IDA* h()函数常见操作:

        1.不在位置上的数,res++

        2.某次操作后,边界关系.

 

posted @ 2021-04-25 01:48  acmloser  阅读(77)  评论(0编辑  收藏  举报