A*算法解决八数码问题时,第N步的解空间是多少?

本文探讨了在解决八数码问题时如何通过广度优先策略、哈希表和回溯法统计解空间的大小,以优化算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们在解决八数码问题是,会关心一个解空间的问题,比如我们进行了27步操作时,当前状态有多少可能的方案呢?
统计解空间的大小,有助于我们更好的优化算法。


  1. 我们可以利用广度优先策略,来统计第N步的可能方案。
  2. 利用hash表来存储可行方案,从而剔除重复方案。
  3. 利用回溯的方式,从第N步开始往起点回退,能回退到起点的方案就是可能性方案,记录该方案。

下面就是我们统计八数码问题进行到第27步以后,统计解空间大小的代码:

#include <iostream>
#include <set>
#include <vector>
#include <queue>

using namespace std;

//向四个方向生成新的方案
int x_axis[] = {-1,  0, 0, 1};
int y_axis[] = { 0, -1, 1, 0};

/**
 *generate函数:生成新的一层解决方案
 *
 *@param queue<vector<int>> myqueue, set<vector<int>> myset;
 */
void generate(queue<vector<int> > &nodes, set<vector<int> > &states)
{
  //拓展已经经过的所有节点
  vector<int> layer;
  //使用空的向量来区分不同层的树枝
  nodes.push(layer);

  //拓展当前层的所有节点
  while(nodes.front().size() != 0)
  {
    vector<int> current = nodes.front();

    //拓展当前节点
    //寻找0的位置
    int px;
    int py;

    for(int i = 0; i < 9; ++i)
    {
      if(current[i] == 0)
      {
        px = i / 3;
        py = i % 3;
      }
    }
    //想四个方向拓展,首先得判断能否拓展
    for(int i = 0; i < 4; i++)
    {
      if(px+x_axis[i] >= 0 && px+x_axis[i] < 3 &&
         py+y_axis[i] >= 0 && py+y_axis[i] < 3)
      {
        vector<int> fresh = current;
        fresh[px*3+py] = fresh[(px+x_axis[i])*3+(py+y_axis[i])];
        fresh[(px+x_axis[i])*3+(py+y_axis[i])] = 0;

        //在哈希表中寻找新生成的节点是否已经出现过,如果出现过就抛弃。
        if(states.find(fresh) == states.end())
        {
          states.insert(fresh);
          nodes.push(fresh);
        }
      }
    }
    //将已经遍历的点推出队列
    nodes.pop();
  }
  //将队列中标识分层的空向量删除掉
  nodes.pop();

  //清空哈希表
  //states.clear();

  cout<<nodes.size()<<endl;

  return;
}

int main(int argc, char *argv[])
{
  //构造目标状态的数据
  vector<int> goal;

  for(int i = 0; i < 9; ++i)
  {
    goal.push_back(i);
  }

  //给定循环的次数
  int times = 27;

  //初始化队列和哈希表
  queue<vector<int> > nodes;
  set<vector<int> > states;

  nodes.push(goal);
  states.insert(goal);

  while(times--)
  {
    generate(nodes, states);
  }

  //输出哈希表的大小
  cout<<"搜索空间大小为:"<<nodes.size()<<endl;

  return 0;
}
include using namespace std; struct node{ int nodesun[4][4]; int pre; //上一在队列中的位置 int flag ; //数标识,表示当前的数为有效的 int value; //与目标的差距 int x,y; //空格坐标 }queue[1000]; //移动方向数组 int zx[4]={-1,0,1,0}; int zy[4]={0,-1,0,1}; //当前数 int top; int desti[4][4];//目标状态 int detect(struct node *p)//检查是否找到 {int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) return 0; return 1; } //打印 void printlj() {int tempt; int i,j; tempt=top; while(tempt!=0) { for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<queue[tempt].nodesun[i][j]; if(j==3) cout<<" "<<endl; } tempt=queue[tempt].pre; } } //现在状态与目标状态有多少个不同位置 int VALUE(struct node *p) {int count=0; int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) count++; return count; } void main() { //初始化 int i,j,m,n,f; int min=10; int temp,find=0,minnumber; top=1; for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; queue[1].nodesun[i][j]=temp; } cout<<"请输入初始状态的空格的位置(行)"<>temp; queue[1].x=temp; cout<<"请输入初始状态的空格的位置(列)"<>temp; queue[1].y=temp; queue[1].value=VALUE(&queue[1]); queue[1].pre=0; //上一在队列中的位置 queue[1].flag=0; //目标状态 for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入目标状态第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; desti[i][j]=temp; } //根据估价函数 while(!find&&top>0) { for(i=1;i<=top;i++) //////////////////////////////////////////// //min为上一图中与目标图有多少个元素不相同,queue[i]为当前图与目标图有多少个元素不相同通过这两个数的比较,就可以得出当前图较之上一图向目标图接近同把当前的i记录下来进行下一比较 {if(queue[i].value<min&&queue[i].flag==0) {minnumber=i;// min=queue[i].value; //还有多少不同的位数 } } queue[minnumber].flag=1; //表示此位有效 ////////////////////////////////////// // for(f=0;f=1&&i=1&&j<=3) {top++; ///////////////////////////////////////////// //位置交换 queue[top]=queue[minnumber]; queue[top].nodesun[m][n]=queue[minnumber].nodesun[i][j]; queue[top].nodesun[i][j]=0; /////////////////////////////////////// //空格移动方向 queue[top].x=i; queue[top].y=j; /////////////////////////////////////// queue[top].pre=minnumber; //上一在队列中的位置 queue[top].value=VALUE(&queue[top]); //有多少位与目标不同 queue[top].flag=0; //标识位初始化 if(detect(&queue[top])) //检查是否为目标 {printlj(); //打印 find=1; //设找到标识位 break; } } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值