【UVA11212 算法竞赛入门经典】 Editing a Book 【IDA*】

题意

  你有一篇由n(2<=n<=9)个自然段组成的文章,希望将它们排列成1,2,···,n。可以用剪切和粘贴来完成任务。每次可以剪切一段连续的自然段,粘贴时按照顺序粘贴。注意剪贴板只有一个,所以不能连续剪切两次,只能剪切和粘贴交替。

分析

  鄙人真的不擅长搜索,花了两天时间做完搜索专题的作业,然后被这一道题卡了一天,结果今下午的比赛又是搜索专题,我又不知道得补到啥时候···难受!

  这个题是比较显然的IDA*,主要是估值函数h()的计算。如果当前有res个数字的位置不正确,而每次剪切h()最多可以减少3.所以当h()>cur的时候,return false。

  然后还加了一个优化(不影响ac,但是会快不少),就是如果存在连续的一段,在cut的时候不把他们拆开。

  下面是ac的代码

 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 const int maxn=15;
 8 int a[maxn],b[maxn];
 9 int n,kase;
10 bool judge(){
11     for(int i=1;i<=n;i++){
12         if(b[i]!=i)
13             return false;
14     }
15     return true;
16 }
17 void ope(int from,int len,int to){//将从from开始,长度为len的一段序列,复制到to位置,然后to位置到from-1位置原来的元素后延
18     int c[maxn];
19     for(int i=from,j=1;j<=len;i++,j++)
20         c[j]=b[i];
21     if(from>to){
22         for(int i=from-1;i>=to;i--)
23             b[i+len]=b[i];
24         for(int i=to,j=1;j<=len;i++,j++)
25             b[i]=c[j];
26     }else if(from<to){
27         for(int i=from+len;i<=to;i++)
28             b[i-len]=b[i];
29         for(int i=to,j=len;j>=1;i--,j--)
30             b[i]=c[j];
31     }
32 }
33 void recover(int from,int len, int to){
34     if(from<to){
35         ope(to-len+1,len,from);
36     }else if(to<from){
37         ope(to,len,from+len-1);
38     }
39 }
40 
41 bool opeti(int F,int L,int to){
42     if(F!=1)
43         if(b[F-1]+1==b[F])
44           return false;
45     if(F+L-1!=n)
46         if(b[F+L-1]+1==b[F+L])
47           return false;
48     return true;
49 }
50 int h(){
51     int res=0;
52     for(int i=1;i<n;i++)
53         if(b[i]+1!=b[i+1])res++;
54     if(b[n]!=n)res++;
55     return res;
56 }
57 
58 bool dfs(int cur){
59     if(cur==0){
60         if(judge())
61             return true;
62         return false;
63     }
64     if(h()>3*cur)return false;
65     for(int F=1;F<=n;F++){
66         for(int L=1;L<=n-F+1;L++){
67             for(int to=1;to<=n;to++){
68                 if(!opeti(F,L,to))continue;
69                 if(to==F)continue;
70                 if(to>F&&to<=F+L-1)continue;
71                 if(to<F&&to>=F-L+1)continue;
72                 ope(F,L,to);
73                 if(dfs(cur-1))
74                     return true;
75                 recover(F,L,to);
76             }
77         }
78     }
79     return false;
80 }
81 int main(){
82  //   freopen("out.txt","w",stdout);
83     kase=0;
84     while(scanf("%d",&n)!=EOF&&n){
85         for(int i=1;i<=n;i++)
86             scanf("%d",&a[i]);
87         for(int i=1;i<=n;i++)
88             b[i]=a[i];
89         int ans=0;
90         for(int maxd=0;;maxd++){
91             if(dfs(maxd)){
92                 ans=maxd;
93                 break;
94             }
95         }
96         printf("Case %d: %d
",++kase,ans);
97     }
98 return 0;
99 }
View Code
原文地址:https://www.cnblogs.com/LQLlulu/p/9427092.html