UVA 11212 Editing a Book

迭代加深搜索:对于可以用回溯法求解但解答树的深度没有明显上限的题目,可以考虑用迭代加深搜索。例如:埃及分数问题

迭代加深搜索就是从小到大枚举深度上限maxd,每次执行只考虑深度不超过maxd的结点。这样,只要解的深度有限,则一定可以在有限时间内枚举到。深度的上限还可以用来剪枝,剪枝的关键在于:可以估计至少还有多少步才能出解。注意,这里的估计都是乐观的,因为用于“至少”这个词。就是说,设深度上限为maxd,当前结点n的深度为g(n),乐观估价函数为h(n),则当g(n)+h(n)>maxd时应该剪枝,这样的算法就是IDA*,主要是设计乐观估价函数,想清楚在什么情况下不可能在当前的深度限制下出解即可。如果可以设计出一个乐观估价函数,预测从当前结点至少还需要扩展几层结点才有可能得到解。

主框架:

 

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

 

 

 

 

 

题意:有n个数,希望将它们排成1,2,3,...,n。可以用剪切和粘贴来完成任务,每次可以剪切一段连续的自然段,粘贴时按照顺序粘贴。注意,剪贴板只有一个,所以不能连续剪切两次,只能剪切和粘贴交替

解题思路:典型的状态空间搜索问题,“状态”就是1~n的排列,初始状态是输入,终止状态是1,2,3,...,n。因为n<=9,排列最多有9!=362880个。虽然这个数字不大,但是每个状态的后继状态也比较多(有很多剪切和粘贴的方式),所以仍有超时的危险。本题可以用IDA*算法求解,不难发现n<=9时最多只需要8步,因此深度上限为8,IDA*的关键在于剪枝函数。考虑后继不正确的数字的个数h,可以证明每次剪切时h最多减少3,因此当3*d+h>3*maxd时就可以剪枝,其中d为当前深度,maxd为深度限制。至于h最多减少3是因为,假如原来是abcd,现在剪切变成acbd,那么只有a,b,c三个数字的后继变了

代码:

 

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int n;
int book[15];
bool is_success()//判断是否成功
{
    for(int i=0;i3*maxd)return false;//剪枝,因为移动一个片段最多改变三个后继
    if(is_success())return true;
    int last_book[15];//因为扩展节点后book会随之改变,为了保存原来的book
    for(int i=0;ij)temp[cnt++]=book[k];//剪切后的剩余部分
            }
            for(int l=0;l>n&&n)
    {
        for(int i=0;i>book[i];
        }
        int k=solve();
        cout<<"Case "<<++cas<<": "<

 

 

 

 

 

你可能感兴趣的:(OJ刷题)