UVa 11212 Editing a Book (编辑书稿)迭代加深

初看这道题,方法肯定用搜索。。不过想想,搜索的宽度和深度又是个问题。所以就用迭代加深

什么是迭代加深,从加深来看,就是一开始只搜第一层,深度超过1时强行退出,第二次只搜2层,就这样一直往下,直到找到最优解。

那么为什么要用他呢??迭代加深的优点:1.不会像DFS一样一直找到叶子节点(转牛角尖),2.不会像BFD内存爆掉(相当于改进过的DFS,可以一层一层搜索,只不过顺序还是DFS)

也可以说,迭代加深的思想之一为,枚举答案ANS,再讲ANS带入DFS,看是否满足,而一般的搜索恰好相反,为直接BFS枚举答案。

要用迭代加深,那么最好要有一个好的启发式函数(剪枝用)。

代码我准备分为一个个函数来讲。


首先是判断找到答案:

bool is_sorted() {
  for(int i = 0; i < n-1; i++)
    if(a[i] >= a[i+1]) return false;//也就是查看是否已排好序
  return true;
}

第二,启发式函数(可以看做是)

int h() {
  int cnt = 0;
  for(int i = 0; i < n-1; i++)
    if(a[i]+1 != a[i+1]) cnt++;
  if(a[n-1] != n) cnt++;
  return cnt;
}
h()这个函数用处是取出顺序不正确的数字的个数,通过公式3d+h()>3max来判断当前搜索的最大层数是否合理

当3d+h()>3max时,我们的最大搜索层数maxd就小了,所以返回,再把maxd加大。


三,DFS函数

bool dfs(int d, int maxd) {
  if(d*3 + h() > maxd*3) return false;//上面说的剪枝
  if(is_sorted()) return true;//递归边界

  int b[maxn], olda[maxn];//临时数组,和旧的a数组
  memcpy(olda, a, sizeof(a));//复制数组
  for(int i = 0; i < n; i++)
   for(int j = i; j < n; j++) {//这里是枚举剪切的头和尾,i代表从哪里开始剪切,j表示剪切到哪里,故j要从i开始
     int cnt = 0;//计数
     for(int k = 0; k < n; k++)
       if(k < i || k > j) b[cnt++] = a[k];//这句话作用是将未被剪切的字母放到B数组中

     for(int k = 0; k <= cnt; k++) {//这里就是枚举插入的位置
       int cnt2 = 0;
       for(int p = 0; p < k; p++) a[cnt2++] = b[p];//从第K位插入,则将K前的元素先加到数组中
       for(int p = i; p <= j; p++) a[cnt2++] = olda[p];//将被剪切的部分插入
       for(int p = k; p < cnt; p++) a[cnt2++] = b[p];//最后加入K后的元素,相当于把b数组分为两部分,先加第一部分,在加被剪切部分,最后加入第二部分

       if(dfs(d+1, maxd)) return true;//继续搜
       memcpy(a, olda, sizeof(a));//还原数组
     }
   }
  return false;
}
第四,枚举答案部分,这部分相对简单

int solve() {
  if(is_sorted()) return 0;//这里不用解释
  int max_ans = 5; // 经过测试,当n<=9时,ans<=5
  for(int maxd = 1; maxd < max_ans; maxd++)//设置搜索最大层数,其实变相的也是在枚举答案
    if(dfs(0, maxd)) return maxd;//因为可以保证第一次搜到答案时一定是最短路径,而搜索层数就是路径的长度
  return max_ans;//搜不到返回最大答案
}

好吧,最后一个主函数了
int main() {
  int kase = 0;
  while(scanf("%d", &n) == 1 && n) {
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    printf("Case %d: %d\n", ++kase, solve());
  }
  return 0;
}

输入输出不解释


最后发完整代码大笑大笑大笑

#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 9;
int n, a[maxn];

bool is_sorted() {
  for(int i = 0; i < n-1; i++)
    if(a[i] >= a[i+1]) return false;
  return true;
}

int h() {
  int cnt = 0;
  for(int i = 0; i < n-1; i++)
    if(a[i]+1 != a[i+1]) cnt++;
  if(a[n-1] != n) cnt++;
  return cnt;
}

bool dfs(int d, int maxd) {
  if(d*3 + h() > maxd*3) return false;
  if(is_sorted()) return true;

  int b[maxn], olda[maxn];
  memcpy(olda, a, sizeof(a));
  for(int i = 0; i < n; i++)
   for(int j = i; j < n; j++) {
     // cut
     int cnt = 0;
     for(int k = 0; k < n; k++)
       if(k < i || k > j) b[cnt++] = a[k];

     for(int k = 0; k <= cnt; k++) {
       int cnt2 = 0;
       for(int p = 0; p < k; p++) a[cnt2++] = b[p];
       for(int p = i; p <= j; p++) a[cnt2++] = olda[p];
       for(int p = k; p < cnt; p++) a[cnt2++] = b[p];

       if(dfs(d+1, maxd)) return true;
       memcpy(a, olda, sizeof(a));
     }
   }
  return false;
}

int solve() {
  if(is_sorted()) return 0;
  int max_ans = 5;
  for(int maxd = 1; maxd < max_ans; maxd++)
    if(dfs(0, maxd)) return maxd;
  return max_ans;
}

int main() {
  int kase = 0;
  while(scanf("%d", &n) == 1 && n) {
    for(int i = 0; i < n; i++) scanf("%d", &a[i]);
    printf("Case %d: %d\n", ++kase, solve());
  }
  return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值