zoukankan      html  css  js  c++  java
  • POJ 3460 Booksort(IDA* + 估价函数设计)

    题意:

    有N(1 ≤ N ≤ 15)本书,每本与每本的高度都不一样。现在可以按照以下的办法整理书:抽出一摞书,再保持原来的顺序插进一个位置。

    这样的话我们称之为“一次操作”。现在你需要求出至少需要经过几次操作才能让书变成按高度升序的状态。如果需要5次或者多于5次,只需要输出“5 or more”。

    思路:

    1. 题目中已经有个很明显的提示:最多不超过 5 次。于是便可以用 IDA* + 暴力枚举试图去解决问题;

    2. IDA* 不难,暴力也不难,难的是如果根据状态设计启发式函数:由于每次操作,最多能改变 3 个元素的后继,所以根据这个信息点来设计启发式函数能满足要求;

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    int books[20], N;
    
    void swapbooks(int p, int x, int q) {
        int buffer[20], c = 0;
        for (int i = x + 1; i <= q; i++)
            buffer[c++] = books[i];
        for (int i = p; i <= x; i++)
            buffer[c++] = books[i];
        for (int i = p; i <= q; i++)
            books[i] = buffer[i-p];
    }
    
    int getdiff() {
        int h = 0;
        for (int i = 0; i < N - 1; i++) {
            if (books[i] + 1 != books[i+1])
                h += 1;
        }
        if (books[N-1] != N)
            h += 1;
        return (h + 2) / 3;
    }
    
    int maxdepth;
    bool succ;
    
    int dfs(int depth) {
        int h = getdiff();
        if (h == 0) {
            succ = true;
            return depth;
        }
        int f = depth + h;
        if (f > maxdepth)
            return f;
    
        int newbound = 1e9;
        for (int p = 1; p < N; p++) {
            for (int i = 0, j = i + p; j < N; i++, j++) {
                for (int k = i; k < j; k++) {
                    swapbooks(i, k, j);
                    int f = dfs(depth + 1);
                    if (succ)
                        return f;
                    newbound = min(f, newbound);
                    swapbooks(i, i + j - k - 1, j);
                }
            }
        }
        return newbound;
    }
    
    int main() {
        int cases;
        scanf("%d", &cases);
        while (cases--) {
            scanf("%d", &N);
            for (int i = 0; i < N; i++)
                scanf("%d", &books[i]);
    
            maxdepth = getdiff();
            if (maxdepth)
                succ = false;
            else
                succ = true;
            while (!succ && maxdepth < 5) 
                maxdepth = dfs(0);
    
            if (!succ)
                printf("5 or more\n");
            else
                printf("%d\n", maxdepth);
        }
        return 0;
    }
  • 相关阅读:
    登录验证servlet实现
    IOS开发(68)之捕获点击划屏手势
    jquery实现漂浮在网页右侧的qq在线客服插件
    深切缅怀“5.12”特大地震遇难同胞
    PHP实现微信申请退款流程实例源码
    empty和isset的区别
    ThinkPHP中实现微信支付(jsapi支付)流程
    php中正则表达式详解
    PHP与RBAC设计思路讲解与源码
    一起谈.NET技术,VS2010实践RUP4+1架构模型 狼人:
  • 原文地址:https://www.cnblogs.com/kedebug/p/2994282.html
Copyright © 2011-2022 走看看