zoukankan      html  css  js  c++  java
  • UVA 11212 Editing a Book [迭代加深搜索IDA*]

     

                            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.状态转移:以长度递增的顺序,依次从每个元素开始剪切相应长度的一段,然后依次插入后继元素之后(用链表存储序列更方便剪切和插入操作)。

    代码如下(关键内容有注释):

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <set>
      5 #include <algorithm>
      6 #include <ctime>
      7 using namespace std;
      8 
      9 #define print_time_ printf("time : %f
    ",double(clock())/CLOCKS_PER_SEC)
     10 const int maxn=9;
     11 set<int> v;//存储状态
     12 int next_[maxn+2];//用链表存储当前序列
     13 int n;
     14 int maxd;
     15 
     16 inline int Atoi(int *next){ //将当前序列转换成十进制数
     17     int ans=0;
     18     for(int i=next[0],j=0;j<n;j++,i=next[i])
     19         ans=ans*10+i;
     20     return ans;
     21 }
     22 inline bool isvisited(int *A){//判重
     23     return v.count(Atoi(A));
     24 }
     25 inline void push_v(int *A){
     26     v.insert(Atoi(A));
     27 }
     28 int h(int *next){//获得当前状态下的错数
     29     int h=0;
     30     for(int i=next[0],j=1;j<=n;j++,i=next[i]){
     31         if(j<n){
     32             if(i==n||(i!=n&&next[i]!=i+1))
     33                 h++;
     34         }
     35         else if(i!=n)
     36             h++;
     37     }
     38     return h;
     39 }
     40 int get_r(int& l,int& len){ //获得被剪切段的最右端
     41     int r=l;
     42     for(int i=0;i<len-1;i++)
     43         r=next_[r];
     44     return r;
     45 }
     46 bool IDA(int d){
     47     if(d==maxd){
     48         if(h(next_)==0)
     49             return true;
     50         else return false;
     51     }
     52     int h_=h(next_);
     53     if(h_>3*(maxd-d))
     54         return false;
     55     for(int len=1;len<n;len++){
     56         for(int last=0,l=next_[0],j=1;j+len-1<=n;j++,last=l,l=next_[l]){
     57             
     58             int r=get_r(l, len);
     59             
     60             for(int ptr=next_[r],i=j+len;i<=n;i++,ptr=next_[ptr]){
     61                 
     62                 next_[last]=next_[r];
     63                 next_[r]=next_[ptr];
     64                 next_[ptr]=l;
     65                 
     66                 if(!isvisited(next_)){
     67                     
     68                     push_v(next_);//被访问
     69                     if(IDA(d+1))
     70                         return true;
     71                     v.erase(Atoi(next_));//不要漏掉这一句!!
     72                 }
     73                 next_[ptr]=next_[r];
     74                 next_[r]=next_[last];
     75                 next_[last]=l;
     76                
     77                 
     78             }
     79         }
     80     }
     81     return false;
     82 }
     83 void init(){
     84     memset(next_, 0, sizeof next_);
     85     v.clear();
     86 }
     87 int main() {
     88     int T=0;
     89     while(scanf("%d",&n)&&n){
     90         T++;
     91         init();
     92         for(int i=0,j=0;j<n;i=next_[i],j++){
     93             scanf("%d",&next_[i]);
     94         }
     95         
     96         for(maxd=0;;maxd++){
     97             v.clear();
     98             push_v(next_);
     99             if(IDA(0)){
    100                 printf("Case %d: %d
    ",T,maxd);
    101                 break;
    102             }
    103         }
    104     }
    105     //print_time_;
    106     return 0;
    107 }

      

  • 相关阅读:
    hdu 4638 Group 线段树
    hdu 4635 Strongly connected 强连通分量
    hdu 4604 Deque
    hdu 1000 A + B Problem
    数组相关
    文本文件相关
    硬件电路中VCC,VDD,VEE,VSS有什么区别
    VIPM链接LabVIEW问题
    Touch实现轻扫
    touchesMoved 实现拖拽
  • 原文地址:https://www.cnblogs.com/Kiraa/p/5297446.html
Copyright © 2011-2022 走看看