uva11212 编辑书稿 迭代加深

  1. 迭代加深,逐层计算。
  2. 乐观估价函数,剪枝。
  3. 递归枚举,利用数组保存数据,之后恢复。
  4. 剪切一个片段并粘贴,最多改变3个后缀。
  5. 迭代加深的基本框架。

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23956
框架:

is_success()//是否成功
h()//估价函数,用于剪枝
dfs()//遍历
{
    is_success();
    h();//利用h()判断是否应该剪枝
    for()//递归枚举
    {
        保存目前状态。
        递归枚举深入。
        恢复状态。//可以利用memcpy()高效复制
    }
}
solve()//迭代加深基本框架
{
    if(is_success)//有时可以不用此判断。
    int max_ans;//可能的最深
    for(maxd = 0;;maxd++)
    {
        if(dfs(0,maxd))
            return maxd;
    }
    return max_ans;
}

此题的标准代码:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn = 10;

int n, book[maxn];

bool is_goal() {//判断是否成功
    bool ok = true;
    for(int i = 0; i < n; i++) {
        if(book[i] != i + 1) {
            ok = false;
            break;
        }
    }
    return ok;
}

int h() {//判断一共有几个移动的小片段
    int cnt = 0;
    for(int i = 0; i < n - 1; i++) {
        if(book[i] + 1 != book[i + 1])
            cnt++;
    }
    if(book[n - 1] != n)    cnt++;
    return cnt;
}


bool dfs(int d, int maxd) {
    if(3 * d + h() > maxd * 3)  return false;           //剪枝,因为移动一个片段最多改变三个后缀
    if(is_goal())               return true;

                                                        //扩展节点同时进行加深搜索
    int old_book[maxn];                                 //因为扩展节点后book会随之改变,为了保存原来的book
    int past_to[maxn];                                  //保存要剪切后的部分
    for(int i = 0; i < n; i++)
    for(int j = i; j < n; j++) {                        //依次枚举要剪切的部分,i是左端开头,j是右端结尾
        memcpy(old_book, book, sizeof(book));           //保存原来book

        int cnt = 0;
        for(int k = 0; k < n; k++)
            if(k < i || k > j)
                past_to[cnt++] = book[k];               //剪切后的部分

        for(int k = 0; k <= cnt; k++) {                 //依次枚举要插入第k位置前面
            int cnt2 = 0;                               //执行粘贴操作
            for(int p = 0; p < k; p++)      book[cnt2++] = past_to[p];
            for(int p = i; p <= j; p++)     book[cnt2++] = old_book[p];
            for(int p = k; p < cnt; p++)    book[cnt2++] = past_to[p];

            if(dfs(d + 1, maxd))    return true;        //加深搜索
            memcpy(book, old_book, sizeof(old_book));   //如果加深搜索失败的话就返回原来的数组状态
        }//枚举了每一种情况,并在结束恢复状态。
    }
    return false;
}

int solve() {//迭代加深基本模板
    if(is_goal())   return 0;
    for(int maxd = 0; maxd < 9; maxd++)                 //枚举层数,最多不超过9层dfs即可求出答案
        if(dfs(0, maxd))    return maxd;
    return -1;
}

int main()
{
    //freopen("input.txt", "r", stdin);
    int kase = 0;
    while(~scanf("%d", &n) && n) {
        memset(book, 0, sizeof(book));
        for(int i = 0; i < n; i++)  scanf("%d", &book[i]);
        printf("Case %d: %d\n", ++kase, solve());
    }
    return 0;
}

在林伏案的博客上加了一些修改,代码来自http://blog.csdn.net/qq_29169749/article/details/51419907

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值