【算法竞赛入门经典】7.6 迭代加深搜索与IDA* 例题7-10 UVa11211

【算法竞赛入门经典】7.6 迭代加深搜索与IDA* 例题7-10 UVa11211

例题UVa11211

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

分析。

其实本题十分适合直接使用BFS。本质上就是一个BFS求不同状态之间的最短路径问题嘛。但是,可以用来当做迭代加深搜索和IDA*搜索的例题来看。

迭代加深搜索 & IDA*

迭代加深搜索(Iterative Deepening Depth-First Search, IDDFS)经常用于理论上解答树深度上没有上界的问题,这类问题通常要求出满足某些条件时的解即可。比如在“埃及分数”问题中要求将一个分数a/b分解成为若干个形如1/d的加数之和,而且加数越少越好,如果加数个数相同,那么最小的分数越大越好。下面总结一下该方法的一般流程:
概述:迭代加深搜索是通过限制每次dfs的最大深度进行的搜索。令maxd表示最大的搜索深度,那么dfs就只能在0~maxd之间来进行,如果在这个范围内找到了解,就退出大循环,否则maxd++,扩大搜索范围。但可想而知,倘若没有高效及时的退出无解的情况,那么时间上的开销也是会比较大的。这时就需要进行“剪枝”操作,及时地判断此时能否找到解。对于迭代加深搜索,经常通过设计合适的“乐观估价函数”来判断能否剪枝。设当前搜索的深度是cur,乐观估价函数是h(),那么当cur+h()>maxd时就需要剪枝。
那么什么是乐观估价函数呢?简单的说就是从当前深度到找到最终的解“至少”还需要多少步,或者距离找到最终的解还需要扩展多少层。如果超出了当前限制的深度maxd,说明当前限制的最大深度下是不可能找到解的,直接退出。比如像前面的“埃及分数”问题,要拆分19/45这样的一个分数,假设当前搜索到了第三层,得到19/45=1/5+1/100…那么根据题意此时最大的分数为1/101,而且如果需要凑够19/45,需要(19/45-1/5-1/100)*101=23个1/101才行。即从第3层还要向下扩展至少大于23层的深度才可能找到所有的解。所以如果此时的maxd<23,就可以直接剪枝了。因此(a/b-c/d)/(1/e)便是本题的乐观估价函数。
注意,使用迭代加深搜索时要保证一定可以找到解,否则会无限循环下去。
CSDN——XDU_Skyline

就是说,当宽度优先搜索数据量过于庞大甚至每一层都无上限的情况下,可以用迭代加深搜索来解决求最短路的问题。
设想宽度无限、深度无限,那求最短路的时候不能直接套用BFS也不能DFS之后求最小值。这种情况下就可以用迭代加深搜索来一层层的限定,最大层数从1往上加,一旦找到了,最大层数就是最短路。这样使用DFS来进行搜索,此时要注意寻找终止条件。即:宽度不能使随意选取的无限量,必定超过某个阈值之后就不符合条件,此时结束搜索。
另外,若是利用最大层数等等,得出剩余至少搜索数量,判断出已经无法满足要求的时候,就果断剪枝,这实际上就叫IDA*搜索。即:当前搜索层数条件加上剩余最小搜索成功条件比MaxDepth条件还要大的时候,就不可能得到有解的情况。

本题储存结构

利用a数组记录每组数据。
利用op保存每组数据的备份以便恢复
利用bo数组保存在确定剪切范围为[i,j]的情况下,剩余数据有哪些。
这样,就枚举所有可能的[i,j]下,将其插到剩余数据的任意位置。插入完成后,判断是否成功或及进行下一层搜索。

样例实现代码

#include<iostream>
#include<cstring>
#define max 9
using namespace std;
int a[max], n;
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 is_solved() {
    for (int i = 0; i < n; i++)
        if (a[i] != i + 1)
            return false;
    return true;
}
bool dfs(int d, int dmax) {
    if ((dmax - d) * 3 < h())
        return false;
    if (is_solved())
        return true;
    int op[max], bo[max];
    memcpy(op, a, sizeof(a));
    for (int i = 0; i < n; i++) {
        for (int j = i; j < n; j++) {
            int cnt1 = 0;
            for (int k = 0; k < n; k++) {
                if (k < i || k>j)
                    bo[cnt1++] = a[k];
            }
            for (int k = 0; k <= cnt1; k++) {
                int cnt2 = 0;
                for (int p = 0; p < k; p++) {
                    a[cnt2++] = bo[p];
                }
                for (int p = i; p <= j; p++) {
                    a[cnt2++] = op[p];
                }
                for (int p = k; p < cnt1; p++) {
                    a[cnt2++] = bo[p];
                }
                if (dfs(d + 1, dmax))
                    return true;
                memcpy(a, op, sizeof(a));
            }
        }
    }
    return false;
}
int sol() {
    if (is_solved())
        return 0;
    for (int i = 1; i <= n; i++)
        if (dfs(0, i))
            return i;
}
int main() {
    int kase = 1, ans;
    while (cin >> n && n) {
        for (int i = 0; i < n; i++)
            cin >> a[i];
        cout << "Case " << kase++ << ": " << sol() << endl;
    }
    return 0;
}

结果

这里写图片描述

TIP

迭代加深搜索的最典型例题是埃及分数问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值