搜索进阶-迭代加深搜索

我个人对这个搜索的理解就是以BFS的思想写DFS

具体来说就是,首先深度优先搜索k层,若没有找到可行解,再深度优先搜索k+1层,直到找到可行解为止。由于深度是从小到大逐渐增大的,所以当搜索到结果时可以保证搜索深度是最小的。这也是迭代加深搜索在一部分情况下可以代替广度优先搜索的原(还比广搜省空间)。

前提:

题目一定要有解,否则会无限循环下去。

好处:

1.时间复杂度只比BFS稍差一点(虽然搜索k+1层时会重复搜索k层,但是整体而言并不比广搜慢很多)。

2.空间复杂度与深搜相同,却比广搜小很多。

3.利于剪枝。

使用搜索算法的时候,选择正确的搜索方式很重要。当有一类问题需要做广度优先搜索,但却没有足够的空间,而时间却很充裕,碰到这类问题,我们可以选择迭代加深搜索算法。

剪枝操作:

使用迭代加深搜素时没有剪枝操作时,时间开销是非常大的(因为迭代加深搜索是通过限制每次dfs的最大深度进行的搜索。令maxd表示最大的搜索深度,那么dfs就只能在0~maxd之间来进行,如果在这个范围内找到了解,就退出大循环,否则maxd++,扩大搜索范围。所以可想而知,倘若没有高效及时的退出无解的情况,那么时间上的开销也是会比较大的。)

如何及时的退出无解情况呢?这里引入乐观估计函数

乐观估计函数:从当前深度到找到最终的解“至少”还需要多少步,或者距离找到最终的解还需要扩展多少层。如果超出了当前限制的深度maxd,说明当前限制的最大深度下是不可能找到解的,直接退出。(这个函数你只需要乐观的去构造就行了)

题解: https://lo-li.net/1363.html#comment-737

Description

AveryBoy最近迷上了旋转游戏。旋转游戏使用#形板,可以容纳24块方块(见图)。这些块标有数字1,2和3,每种正好有8个。

最初块随放在板子上,你的目标是移动块,使放置在中心方块的八个块具有相同的符号标记。只有一种类型的有效移动,即旋转四条线中的一条,每条线由七个块组成。也就是说,线中的六个块向头部移动一个块,并且头块移动到线的末端。八个可能的移动用大写字母A到H标记。图示出了两个连续的移动,移动A和移动C。

Input

输入包含不超过30个测试用例。每个测试用例只有一行包含24个数字,这些数字是初始配置中块的符号。块的行从上到下列出。对于每一行,块从左到右列出。数字用空格分隔。例如,样例输入中的第一个测试用例对应于图中的初始配置。案件之间没有空行。在结束输入的最后一个测试用例之后,有一行包含单个“0”。

Output

对于每个测试用例,您必须输出两行。第一行包含达到最终配置所需的所有动作。每个动作都是一个字母,从“A”到“H”,并且行中的字母之间不应有任何空格。如果不需要移动,则输出“No moves needed”。在第二行中,您必须在这些移动后输出中心方块中的块数字。如果有多种可能的解决方案,则必须输出使用最少移动次数的解决方案。如果仍有多个可能的解决方案,则必须输出字典顺序中最小的解决方案。不需要在案例之间输出空行。

Sample Input

1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0

Sample Output

AC
2
DDHH
2

HINT

#include<bits/stdc++.h>
using namespace std;
bool flag=false;
char finop[20];
int reverseop[9]={5,4,7,6,1,0,3,2,-1};
int mp[24];
int pos[8][7]=
{
  { 0,2,6,11,15,20,22 },    //A
  { 1,3,8,12,17,21,23 },    //B
  { 10,9,8,7,6,5,4 },       //C
  { 19,18,17,16,15,14,13 }, //D
  { 23,21,17,12,8,3,1 },    //E
  { 22,20,15,11,6,2,0 },    //F
  { 13,14,15,16,17,18,19}, //G
  { 4,5,6,7,8,9,10 }      //H
};
int center[8]={6,7,8,11,12,15,16,17};
 
void option(int op)
{
    int temp=mp[pos[op][0]];
    for (int i=0;i<6;i++)
    {
      mp[pos[op][i]]=mp[pos[op][i + 1]];
    }
    mp[pos[op][6]]=temp;
}
bool cmp(int a,int b)
{
    return a>b;
}
 
int get_h()
{
    int cnt[3]={0,0,0};
    for (int i = 0; i < 8; i++)
    {
        cnt[mp[center[i]] - 1]++;
    }
    sort(cnt,cnt+3,cmp);
    return 8-cnt[0];
}
 
void dfs(int depth,int lastop,int maxdepth)
{
    if(flag)
      return;
    if(depth>maxdepth||depth+get_h()>maxdepth)
      return;
    if(get_h()==0)
    {
      flag=true;
      finop[depth]='\0';
      cout<<finop<<endl;
      cout<<mp[center[0]]<<endl;
      return;
    }
    for(int nextop=0;nextop<8;nextop++)
    {
        if(nextop!=reverseop[lastop])
        {
            option(nextop);
            finop[depth]=nextop+'A';
            dfs(depth+1,nextop,maxdepth);
            option(reverseop[nextop]);
        }
    }
}
 
int main()
{
    while(1)
    {
        for(int i=0;i<24;i++)
        {
            cin>>mp[i];
            if(i==0)
            {
               if(mp[i]==0)
               return 0;
            }
         }
         if(!get_h())
         {
             cout<<"No moves needed"<<endl;
             cout<<mp[center[0]]<<endl;
             continue;
         }
         else
         {
             flag=false;
             for(int maxdepth=1;!flag;maxdepth++)
                dfs(0,8,maxdepth);
         }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hzaukotete/article/details/81226556
今日推荐