八数码

八数码问题

一、问题描述

所谓八数码问题是指:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上。放牌时要求不能重叠。于是,在3×3的数码盘上出现了一个空格。现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列。

二、问题分析

首先,八数码问题包括一个初始状态(strat) 和 目标状态(goal),所谓解八数码问题就是在两个状态间寻找一系列可过渡状态(strat-> strat 1-> strat 2->...->goal)。这个状态是否存在就是我们要解决的第一个问题。如下是初使状态到目标状态图:(0表示空格)

1

2

3

7

4

5

8

0

6

1

2

3

4

5

6

7

8

0

 

 
   

 

 

 

 

三、数据结构

定义结构体Node如下:

typedef struct{

    int num[9];                

    char cur_expension;         //记录是否可以扩展,Y代表可以扩展,N代表不可以

    char Operate;       //表示不可以执行的操作,L代表不能左移,R代表不能右移,

                    //U代表不能上移,D代表不能下移,C代表可以任意移动。

    int father;                     //记录父节点的下标。

}Node;

Node state[MAXSIZE];

四、广度优先搜索

广度优先搜索是指按节点的层次进行搜索,本层的节点没有搜索完毕时,不能对下层节点进行处理,即深度越小的节点越先得到扩展,也就是说先产生的节点先得以扩展处理,直至找到目标为止。求解八数码问题的搜索过程:如图2所示,把所有可能的算符应用到开始节点(即空格上移、空格左移、空格右移、空格下移),图2只是演示了两个扩展结点,如此继续下去,直到发现目标节点。

 

 

 
   

 

 

 

 

                                                        

    

                                          

 

变量定义及函数说明:

#define SUM 100        //限定只搜索前100步,100步以后如果仍然没有搜索到结果,认为无解。

#define MAXSIZE 200  //定义最大数组长度

int n=1;                      //用来记录搜索的步骤

int goal[9]={1,2,3,7,4,5,8,0,6};//所要达到的最终状态,0代表空格

int same(int temp); //判断是否达到了目标状态

void printgoal();       //输出搜索结果

int left(int temp); //将空格进行左移操作

int right(int temp);    //将空格进行右移操作

int up(int temp);       //将空格进行上移操作

int down(int temp); //将空格进行下移操作

void init();           //初始状态参数设置

五、  程序运行结果

从初始状态到目标状态走了42步

 

 

六、源程序如下

#include <iostream>

#include <stdlib.h>

using namespace std;

int same(int temp); //判断是否达到了目标状态

void printgoal();       //输出搜索结果

int left(int temp); //将空格进行左移操作

int right(int temp);    //将空格进行右移操作

int up(int temp);       //将空格进行上移操作

int down(int temp); //将空格进行下移操作

void init();           //初始状态参数设置      

#define SUM 100        //限定只搜索前100步,100步以后如果仍然没有搜索到结果,认为无解

#define MAXSIZE 200    

int n=1;               

int goal[9]={1,2,3,7,4,5,8,0,6};//所要达到的最终状态,0代表空格

 

typedef struct{

    int num[9];                

    char cur_expension;         //记录是否可以扩展,Y代表可以扩展,N代表不可以

    char Operate;       //表示不可以执行的操作,L代表不能左移,R代表不能右移,

                    //U代表不能上移,D代表不能下移,C代表可以任意移动。

    int father;                     //记录父节点的下标。

}Node;

Node state[MAXSIZE];                //将搜索过的状态存储于该数组中。

 

int main()

{

    init();

    if(same(0))

    {

        cout<<"没有必要进行搜索,初始状态即为最终状态!"<<endl;

        while (true);

    }

    for(int i=0;i<SUM;i++)          //开始进行广度搜索,限定搜索上限为100步。

    {

    if(state[i].cur_expension=='Y')

    {

        if(state[i].Operate=='L')

        {      

            up(i);

            right(i);

            down(i);

        }

        if(state[i].Operate=='R')

        {

            left(i);

            up(i);

            down(i);

        }

        if(state[i].Operate=='U')

        {

            left(i);

            right(i);

            down(i);

        }

        if(state[i].Operate=='D')

        {

            left(i);

            up(i);

            right(i);

        }

        if(state[i].Operate=='C')

        {

            left(i);           

            up(i);

            right(i);

            down(i);

        }

    }

    if(n>=SUM)                  //100步以后仍然没有达到所要求的状态,认为无解。

    {

        n--;

        printgoal();

        cout<<"对不起,在所在搜索范围内没有搜索到结果!"<<endl;

        while (true);

    }

    }

    while(1);

 return 0; 

}

int same(int temp)                  //判断是否达到了目标状态。

{

    for(int j=0;j<9;j++)

        if(state[temp].num[j]!=goal[j])

            return 0;

    return 1;

}

void printgoal()                    //输出搜索结果。

{

    for(int j=1;j<=n;j++)

    {

        cout<<"第"<<j<<"步搜索后:"<<endl;

        cout<<state[j].num[0]<<" "<<state[j].num[1]<<" "<<state[j].num[2]<<endl;

        cout<<state[j].num[3]<<" "<<state[j].num[4]<<" "<<state[j].num[5]<<endl;

        cout<<state[j].num[6]<<" "<<state[j].num[7]<<" "<<state[j].num[8]<<endl;

        cout<<endl;

    }

    cout<<"成功搜索得到结果!"<<endl;

}

int left(int temp)                      //将空格进行左移操作。

{

    int j;

    for(j=0;j<9;j++)                //判断空格的位置。

        if(state[temp].num[j]==0)

            break;

    if(j==0||j==3||j==6)

        return 0;

    for(int k=0;k<9;k++)

        state[n].num[k]=state[temp].num[k];

    int tempNum=state[n].num[j-1];      //将移动后的状态赋给state[n]

    state[n].num[j-1]=0;

    state[n].num[j]=tempNum;

    state[temp].cur_expension='N';

    state[n].Operate='R';

    state[n].cur_expension='Y';

    state[n].father=temp;

    if(same(n))                         //判断state[n]是否为最终想得到的状态。

    {

        printgoal();

        while (true);

    }

    n++;

    return 1;

}

int right(int temp)                     //将空格进行右移操作。

{

    int j=0;

    for(;j<9;j++)

        if(state[temp].num[j]==0)

            break;

    if(j==2||j==5||j==8)

        return 0;

    for(int k=0;k<9;k++)

        state[n].num[k]=state[temp].num[k];

    int tempNum=state[n].num[j+1];

    state[n].num[j+1]=0;

    state[n].num[j]=tempNum;

    state[temp].cur_expension='N';

    state[n].Operate='L';

    state[n].cur_expension='Y';

    state[n].father=temp;

    if(same(n))

    {

        printgoal();

        while (true);

    }

    n++;

    return 1;

}

int up(int temp)                        //将空格进行上移操作。

{

    int j=0;

    for(;j<9;j++)

        if(state[temp].num[j]==0)

            break;

    if(j==0||j==1||j==2)

        return 0;

    for(int k=0;k<9;k++)

        state[n].num[k]=state[temp].num[k];

    int tempNum=state[n].num[j-3];

    state[n].num[j-3]=0;

    state[n].num[j]=tempNum;

    state[temp].cur_expension='N';

    state[n].Operate='D';

    state[n].cur_expension='Y';

    state[n].father=temp;

    if(same(n))

    {

        printgoal();

        while (true);

    }

    n++;

    return 1;

}

int down(int temp)                      //将空格进行下移操作。

{

    int j=0;

    for(;j<9;j++)

        if(state[temp].num[j]==0)

            break;

    if(j==6||j==7||j==8)

        return 0;

    for(int k=0;k<9;k++)

        state[n].num[k]=state[temp].num[k];

    int tempNum=state[n].num[j+3];

    state[n].num[j+3]=0;

    state[n].num[j]=tempNum;

    state[temp].cur_expension='N';

    state[n].Operate='U';

    state[n].cur_expension='Y';

    state[n].father=temp;

    if(same(n))

    {

        printgoal();

        while (true);

    }

    n++;

    return 1;

}

void init()                            

{

    Node start;

   cout<<"初始状态为:(0代表空格)"<<endl;//初始的状态的生成。

   for(int i=0;i<9;i++)

   {

       start.num[i]=(i+1)%9;

       cout<<start.num[i]<<" ";

       if((i+1)%3==0)

           cout << endl;

    }

   cout<<endl;

   cout<<"目标状态为:"<<endl;

  for(int i=0;i<9;i++){

      cout<<goal[i]<<" ";

       if((i+1)%3==0)

           cout << endl;

  }

    cout<<endl;

    for(int k=0;k<9;k++)

        if(start.num[k]==0)

            break;

        start.Operate='C';

    start.cur_expension='Y';

    start.father=-1;

    state[0]=start;                                 //将初始状态赋于state[0]。

}

posted @ 2015-06-22 20:12  新绿薄荷  阅读(1069)  评论(0编辑  收藏  举报