UVA 11212 Editing a Book [迭代加深搜索IDA*]
2016-03-20 12:10
447 查看
11212 Editing a Book You have n equal-length paragraphs numbered 1 to n. Now you want to arrange them in the order of 1, 2, . . . , n. With the help of a clipboard, you can easily do this: Ctrl-X (cut) and Ctrl-V (paste) several times. You cannot cut twice before pasting, but you can cut several contiguous paragraphs at the same time - they’ll be pasted in order. For example, in order to make {2, 4, 1, 5, 3, 6}, you can cut 1 and paste before 2, then cut 3 and paste before 4. As another example, one copy and paste is enough for {3, 4, 5, 1, 2}. There are two ways to do so: cut {3, 4, 5} and paste after {1, 2}, or cut {1, 2} and paste before {3, 4, 5}. Input The input consists of at most 20 test cases. Each case begins with a line containing a single integer n (1 < n < 10), thenumber of paragraphs. The next line contains a permutation of 1, 2, 3, . . . , n. The last case is followed by a single zero, which should not be processed. Output For each test case, print the case number and the minimal number of cut/paste operations. Sample Input 6 2 4 1 5 3 6 5 3 4 5 1 2 0 Sample Output Case 1: 2 Case 2: 1
解题思路:
1.简单分析我们可以发现,当n=9时,最多只需要剪切八次即可完成排序。并且全排列数量9!=362880不算很大,所以我们可以将当前排列作为状态,转化成十进制数存入set以便判重。然后逐渐增加解答树的深度(搜索最大深度)进行迭代加深搜索。
2.构造启发函数。本题可以定义一个后继错数:当前状态中,后继元素不正确的元素个数。可以证明,每一次剪切粘贴最多改变3个数的后继数,那么错数最多减少3.比如 1 2 4 3,错数是3,1 2 3 4,错数是0. 假设当前搜索到第d层,最大搜索深度为maxd,那么如果当前状态的错数 h>3*(maxd-d),则说明这个状态无解,剪枝;
3.状态转移:以长度递增的顺序,依次从每个元素开始剪切相应长度的一段,然后依次插入后继元素之后(用链表存储序列更方便剪切和插入操作)。
代码如下(关键内容有注释):
#include <iostream> #include <cstdio> #include <cstring> #include <set> #include <algorithm> #include <ctime> using namespace std; #define print_time_ printf("time : %f\n",double(clock())/CLOCKS_PER_SEC) const int maxn=9; set<int> v;//存储状态 int next_[maxn+2];//用链表存储当前序列 int n; int maxd; inline int Atoi(int *next){ //将当前序列转换成十进制数 int ans=0; for(int i=next[0],j=0;j<n;j++,i=next[i]) ans=ans*10+i; return ans; } inline bool isvisited(int *A){//判重 return v.count(Atoi(A)); } inline void push_v(int *A){ v.insert(Atoi(A)); } int h(int *next){//获得当前状态下的错数 int h=0; for(int i=next[0],j=1;j<=n;j++,i=next[i]){ if(j<n){ if(i==n||(i!=n&&next[i]!=i+1)) h++; } else if(i!=n) h++; } return h; } int get_r(int& l,int& len){ //获得被剪切段的最右端 int r=l; for(int i=0;i<len-1;i++) r=next_[r]; return r; } bool IDA(int d){ if(d==maxd){ if(h(next_)==0) return true; else return false; } int h_=h(next_); if(h_>3*(maxd-d)) return false; for(int len=1;len<n;len++){ for(int last=0,l=next_[0],j=1;j+len-1<=n;j++,last=l,l=next_[l]){ int r=get_r(l, len); for(int ptr=next_[r],i=j+len;i<=n;i++,ptr=next_[ptr]){ next_[last]=next_[r]; next_[r]=next_[ptr]; next_[ptr]=l; if(!isvisited(next_)){ push_v(next_);//被访问 if(IDA(d+1)) return true; v.erase(Atoi(next_));//不要漏掉这一句!! } next_[ptr]=next_[r]; next_[r]=next_[last]; next_[last]=l; } } } return false; } void init(){ memset(next_, 0, sizeof next_); v.clear(); } int main() { int T=0; while(scanf("%d",&n)&&n){ T++; init(); for(int i=0,j=0;j<n;i=next_[i],j++){ scanf("%d",&next_[i]); } for(maxd=0;;maxd++){ v.clear(); push_v(next_); if(IDA(0)){ printf("Case %d: %d\n",T,maxd); break; } } } //print_time_; return 0; }
相关文章推荐
- Shell - 7
- 关于Collection(Set,List)和Map接口
- 水题
- 第三次上机实践项目-项目4-(3)
- c语言将数组全部赋0的方法
- JSZX_HC_2016_R5
- 第八届 省赛水题
- 5-25 念数字
- iOS App国际化
- 新手推荐JSP+JavaBean+Servlet MVC模式用户注册模块
- fgetc() 出现segment faults
- 20145327 《Java程序设计》第三周学习总结
- 约数个数和(数论,莫比乌斯反演)BZOJ3994
- Linux下如何编译并运行C程序
- 从头到尾解析Hash 表算法
- ubuntu14.04下CPU的caffe配置,不成功的朋友请与我(lee)联系,后面附带邮箱
- 选拔赛专用题(2)模板
- 蝶恋花·踏青
- ipv6地址格式
- 【leetcode】Array——Find Minimum in Rotated Sorted Array(153)