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.某次操作后,边界关系.