深度优先、广度优先和A*算法实现的重排九宫问题

原创 2007年10月11日 16:31:00
  • 问题描述

在3×3的方格上分别放置1,2,3,4,5,6,7,8,9的八张排,初始状态为S0,目标状态为Sg,计算出从S0到Sg的方法。


  • 代码及说明
    /******************************************************************************
     * 使用深度优先、广度优先和A*算法解决九宫问题
    *****************************************************************************
    */


    #include
    <stdio.h>
    #include
    <iostream.h>
    #include
    <string.h>
    #include
    <stdlib.h>



    #include
    "data.h"
    #include
    "queue.h"
    #include
    "stack.h"
    #include
    "link.h"


    #define DEEPSEARCH    1    
    #define WIDESEARCH    2    
    #define ASTART    3        

    #define SEARCHTYPE WIDESEARCH   //定义使用广度优先


    //#define SHOWPROCESS    //定义是否显示中间过程



    class SearchTree{    
    private:
    /***********************定义open表的数据类型************************/
    #if SEARCHTYPE==WIDESEARCH
        Queue open;
    #elif SEARCHTYPE==DEEPSEARCH
        Stack open;
    #else    
        Link open;
    #endif


        Stack close;
    public:
        
    void init();    //初始化数据
        void extend();       //扩展close表尾节点并添加进open表
        void moveToClose();    //将open表的头节点移动到close表中
        bool success();        //判断搜索是否成功
        bool openEmpty();    //判断open表是否为空
        void showAnswer();    //显示最终结果
    }
    ;

    void SearchTree::showAnswer(){
        close.show();
    }


    bool SearchTree::openEmpty(){
        
    return open.empty();
    }



    void SearchTree::extend(){
        DATATYPE temp[LINE][ROW],buf[LINE][ROW];
        Data 
    *pid;
        
    int n,m;
        pid
    =close.getTop(*buf);    //将close表的最后一项记录复制到buf中
        for(n=0;n<LINE;n++)
            
    for(m=0;m<ROW;m++)
                
    if(buf[n][m]==0)//寻找buf中0所在的位置,0表示空格
                    goto L1;
    L1:


        memcpy(temp,buf,DATASIZE
    *sizeof(DATATYPE));    
        
    if(n!=0){    //空格上移
            temp[n][m]=temp[n-1][m];
            temp[n
    -1][m]=0;
            
    if(close.exist(*temp)==false) open.push(*temp,&pid);
    #ifdef SHOWPROCESS    
    //宏定义,决定时候输出中间过程
            cout<<"move below data to open table:"<<endl;
            showElement(
    *temp);
            getchar();
    #endif
        }




        memcpy(temp,buf,DATASIZE
    *sizeof(DATATYPE));
        
    if(n!=2){    //空格下移
            temp[n][m]=temp[n+1][m];
            temp[n
    +1][m]=0;
            
    if(close.exist(*temp)==false) open.push(*temp,&pid);
    #ifdef SHOWPROCESS
            cout
    <<"move below data to open table:"<<endl;
            showElement(
    *temp);
            getchar();
    #endif
        }

        
        memcpy(temp,buf,DATASIZE
    *sizeof(DATATYPE));
        
    if(m!=0){    //空格左移
            temp[n][m]=temp[n][m-1];
            temp[n][m
    -1]=0;
            
    if(close.exist(*temp)==false) open.push(*temp,&pid);
    #ifdef SHOWPROCESS
            cout
    <<"move below data to open table:"<<endl;
            showElement(
    *temp);
            getchar();
    #endif
        }


        
        memcpy(temp,buf,DATASIZE
    *sizeof(DATATYPE));
        
    if(m!=2){    //空格右移
            temp[n][m]=temp[n][m+1];
            temp[n][m
    +1]=0;
            
    if(close.exist(*temp)==false) open.push(*temp,&pid);
    #ifdef SHOWPROCESS
            cout
    <<"move below data to open table:"<<endl;
            showElement(
    *temp);
            getchar();
    #endif
        }




    }


    void SearchTree::moveToClose(){
        DATATYPE dt[DATASIZE];
        Data 
    *pid;
        open.pop(dt,
    &pid);
        close.push(dt,
    &pid);    
    }



    bool SearchTree::success(){
        DATATYPE dt[DATASIZE];
        close.getTop(dt);
        
    return memcmp(dt,*sg,DATASIZE*sizeof(DATATYPE))?  false:true;
    }


    void SearchTree::init(){
        open.init();
        close.init();
        
    //初始节点S0
        s0[0][0]=2;s0[0][1]=8;s0[0][2]=3;
        s0[
    1][0]=1;s0[1][1]=0;s0[1][2]=4;
        s0[
    2][0]=7;s0[2][1]=6;s0[2][2]=5;
        
    //目标节点Sg
        sg[0][0]=1;sg[0][1]=2;sg[0][2]=3;
        sg[
    1][0]=8;sg[1][1]=0;sg[1][2]=4;
        sg[
    2][0]=7;sg[2][1]=6;sg[2][2]=5;
        
    //显示信息
        cout<<"s0:"<<endl;
        showElement(
    *s0);
        cout
    <<"sg:"<<endl;
        showElement(
    *sg);
        cout
    <<"any key to continue"<<endl;
        getchar();

        open.push(
    *s0,NULL);
    #ifdef SHOWPROCESS    
        cout
    <<"below data move to open table:"<<endl;
        showElement(
    *s0);
    #endif

    }



    void main(){
    #if SEARCHTYPE==WIDESEARCH
        puts(
    "wide search"); 
    #elif SEARCHTYPE==DEEPSEARCH
        puts(
    "deep search"); 
    #else    
        puts(
    "astart search");
    #endif
        SearchTree st;
        st.init();    
        
    while(1){
            
    //open表为空,问题无解
            if(st.openEmpty()==true){    
                cout
    <<"there is no answer for this question, open table is empty"<<endl;
                exit(
    0);
            }

            
    //将open表的表头移动到close表中
            st.moveToClose();            
            
    //判断是否搜索成功
            if(st.success()==true){        
                cout
    <<"get answer:"<<endl;
                st.showAnswer();
                exit(
    0);
            }

            
    //扩展close表
            st.extend();                
        }

    }

 

/*********************************************************
 * data.h
 * 定义基本的数据类型
*********************************************************
*/



#define DATATYPE int    //定义数据类型
#define LINE    3        //矩阵的行
#define ROW        3        //矩阵的列
#define DATASIZE    LINE*ROW    //矩阵的大小


class Data{        //存储在open和close表中的数据元素
public:
    DATATYPE element[DATASIZE];    
//九宫图以矩阵的方式存放
    Data *pid;            //记录close表中父亲节点的位置
    Data *next,*pre;    //双向链表
    int gx,hx;
}
;

class F{
public:
    
int gx,hx;
    Data 
*addr;
    F 
*next;
}
;

void showElement(const DATATYPE *dt){    //打印数据元素的信息
    int i;
    
for(i=0;i<DATASIZE;i++){
        
if(i%LINE==0)    cout<<endl;
        cout
<<dt[i]<<" ";
    }

    cout
<<endl;
}



DATATYPE s0[LINE][ROW],sg[LINE][ROW];

 

 

/*********************************************************************************
 * link.h
 * 定义链表类,用于A*算法中的open表
********************************************************************************
*/


class Link: public Queue{    //链表类
private:
    Data head;
    F fhead;        
//估价函数临时表
    int len;
public:
    
void init();    //链表初始化
    void show();    //显示链表
    void push(DATATYPE *,Data **);    //数据入队
    void pop(DATATYPE *,Data **);    //数据出队
}
;    


void Link::show(){
    
if(empty()==true)    cout<<"nothing to print, Link is empty"<<endl;
    
else cout<<"there are "<<len<<" members in the Link: "<<endl;
    Data 
*temp=head.next;
    
while(temp){
        cout
<<"f(x)="<<temp->gx+temp->hx<<endl;
        showElement(temp
->element);
        temp
=temp->next;
    }

}





void Link::init(){
    head.next
=head.pid=head.pre=NULL;
    fhead.next
=NULL;
    len
=0;
}





void Link::pop(DATATYPE *dt,Data **pid){
    
if(empty()==true)    {
        cout
<<"warning: pop Link error beacuse of can not pop a empty Link anykey to exit"<<endl;
        getchar();
        exit(
1);
    }

    Data 
*temp=head.next;
    F 
*ftemp;
    ftemp
=new F;
    ftemp
->gx=temp->gx;
    ftemp
->hx=temp->hx;
    ftemp
->addr=temp->pid;
    ftemp
->next=fhead.next;
    fhead.next
=ftemp;
    memcpy(dt,temp
->element,DATASIZE*sizeof(DATATYPE));
    
*pid=temp->pid;
    head.next
=temp->next;
    
if(head.next)    head.next->pre=&head;
    delete temp;
    len
--;
}




void Link::push(DATATYPE *dt,Data **pid){
    
int gx,hx;
    
int n,m,k;
    Data 
*temp,*loc;    
    F 
*ftemp;
    hx
=k=0;
    
/************************* 计算启发函数 h(x)    **************************/
    
for(n=0;n<LINE;n++)        
        
for(m=0;m<ROW;m++)
            
if(dt[k++]!=sg[n][m]) hx++;
    
/************************* 计算 g(x) ************************************/
    
if(fhead.next!=NULL){    //fhead表中存在数据
        for(ftemp=fhead.next;ftemp;ftemp=ftemp->next)
            
if(ftemp->addr=*pid){
                gx
=ftemp->gx+1;
                
break;
            }

            
if(ftemp==NULL)    {
                puts(
"can not caculate function g(x), program will exit");
                exit(
1);
            }

    }

    
else{    //fhead表为空
        gx=0;    //根节点
    }

    
/******************************创建新数据********************************/
    temp
=new Data;    
    memcpy(temp
->element,dt,DATASIZE*sizeof(DATATYPE));        //将dt复制给temp
    temp->gx=gx;            
    temp
->hx=hx;
    
if(pid!=NULL)    temp->pid=*pid;
    
else temp->pid=NULL;
    temp
->pre=temp->next=NULL;
    
/******************************将数据添加到链表中**********************/
    
if(head.next==NULL){    //链表为空
        head.next=temp;
        temp
->pre=&head;
        temp
->next=NULL;
        
++len;
        
return    ;
    }

    
else{    //链表不空
        loc=head.next;
        
while(1){
            
if((temp->gx+temp->hx)<=(loc->gx+loc->hx)){
                loc
->pre->next=temp;
                temp
->pre=loc->pre;
                temp
->next=loc;
                loc
->pre=temp;
                
++len;
                
return;
            }

            
else if(loc->next==NULL){
                loc
->next=temp;
                temp
->next=NULL;
                temp
->pre=loc;
                
++len;
                
return;
            }

            
else{
                loc
=loc->next;
            }

        }

    }

}


 

 

/**************************************************************************
 * queue.h
 * 定义队列类,用广度优先的open表
*************************************************************************
*/


class Queue: private Data{    //队列类
private:
    Data head,
*loc;
    
int len;
public:
    
int length();    //返回队列的长度
    void init();    //队列初始化
    bool empty();    //判断队列是否为空
    void show();    //显示队列
    bool exist(DATATYPE *);        //判断数据是否之前已经在队列中出现过
    void push(DATATYPE *,Data **);    //数据入队
    void pop(DATATYPE *,Data **);    //数据出队
    Data * getTop(DATATYPE *);    //返回队头元素
}
;


void Queue::show(){
    
if(empty()==true)    cout<<"nothing to print, queue is empty"<<endl;
    
else cout<<"there are "<<len<<" members in the queue: "<<endl;
    Data 
*temp=head.next;
    
while(temp){
        showElement(temp
->element);
        temp
=temp->next;
    }

}



bool Queue::exist(DATATYPE *dt){
    Data 
*temp=head.next;
    
while(temp){
        
if(memcmp(dt,temp->element,DATASIZE*sizeof(DATATYPE))==0)    return true;
        temp
=temp->next;
    }

    
return false;
}


Data 
* Queue::getTop(DATATYPE *dt){
    memcpy(dt,head.next
->element,DATASIZE*sizeof(DATATYPE));
    
return head.next;
}


void Queue::pop(DATATYPE *dt,Data **pid){
    
if(empty()==true)    {
        cout
<<"warning: pop queue error beacuse of can not pop a empty queue anykey to exit"<<endl;
        getchar();
        exit(
1);
    }

    Data 
*temp=head.next;
    memcpy(dt,temp
->element,DATASIZE*sizeof(DATATYPE));
    
*pid=temp->pid;
    head.next
=temp->next;
    
if(head.next)    head.next->pre=&head;
    delete temp;
    len
--;
    
if(len==0)    loc=&head;
}


void Queue::push(DATATYPE *dt,Data **pid){
    Data 
*temp=loc;
    loc
=loc->next=new Data;
    memcpy(loc
->element,dt,DATASIZE*sizeof(DATATYPE));
    
if(pid!=NULL)    loc->pid=*pid;
    
else loc->pid=NULL;
    loc
->next=NULL;
    loc
->pre=temp;
    len
++;
}


void Queue::init(){
    head.next
=head.pid=head.pre=NULL;
    loc
=&head;
    len
=0;
}


bool Queue::empty(){
    
return len==0? true:false;
}


int Queue::length(){
    
return len;
}

 

 

/*********************************************************************************
 * stack.h
 * 定义栈类,用于三种算法的close表以及深度优先搜索的open表
**********************************************************************************
*/


class Stack{    //栈类
private:
    Data head,
*loc;
    
int len;
public:
    
void init();    //初始化栈
    int length();    //返回栈的长度
    bool empty();    //判断栈是否为空
    void show();    //显示栈
    bool exist(DATATYPE *dt);    //判断元素是否在栈中已经出现过
    void push(DATATYPE *,Data **);    //数据入栈
    void pop(DATATYPE *,Data **);    //数据出栈
    Data * getTop(DATATYPE *);        //返回栈顶元素
}
;

void Stack::show(){
    
if(empty()==true)    cout<<"stack is emtpy "<<endl;
    
else    cout<<"there are "<<len<<" members in the stack"<<endl;
    Data 
*temp=loc;
    
int i=0;
    
while(temp){
        cout
<<"step "<<i++<<" :"<<endl;
        showElement(temp
->element);
        temp
=temp->pid;
    }

}



bool Stack::exist(DATATYPE *dt){
    Data 
*temp=head.next;
    
while(temp){
        
if(memcmp(temp->element,dt,DATASIZE*sizeof(DATATYPE))==0)    return true;
        temp
=temp->next;
    }

    
return false;
}


Data 
*Stack::getTop(DATATYPE *dt){
    memcpy(dt,loc
->element,DATASIZE*sizeof(DATATYPE));
    
return loc;
}


void Stack::pop(DATATYPE *dt,Data **pid){
    
if(empty()==true){
        cout
<<"warning: pop stack error beacuse of stack is empty anykey to exit"<<endl;
        getchar();
        exit(
1);
    }

    Data 
*temp=loc;
    loc
=loc->pre;
    loc
->next=NULL;
    memcpy(dt,temp
->element,DATASIZE*sizeof(DATATYPE));
    
*pid=temp->pid;
    delete temp;
    len
--;
}


void Stack::push(DATATYPE *dt,Data **pid){
    Data 
*temp=loc;
    loc
=loc->next=new Data;
    memcpy(loc
->element,dt,DATASIZE*sizeof(DATATYPE));
    
if(pid!=NULL)    loc->pid=*pid;
    
else loc->pid=NULL;
    loc
->next=NULL;
    loc
->pre=temp;
    len
++;
}


void Stack::init(){
    head.next
=head.pid=head.pre=NULL;
    loc
=&head;
    len
=0;
}


int Stack::length(){
    
return len;
}


bool Stack::empty(){
    
return len==0? true:false;
}

蓝桥杯 九宫重排

历届试题 九宫重排   时间限制:1.0s   内存限制:256.0MB        问题描述   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格...
  • qq_33729889
  • qq_33729889
  • 2016-05-26 22:37:02
  • 2485

重排九宫三种算法

  • 2012年06月14日 19:48
  • 110KB
  • 下载

蓝桥杯 历届试题 九宫重排 经典八数码问题 A*算法+康托展开

问题描述   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。   我们把第一个图的局面...
  • Lionel_D
  • Lionel_D
  • 2015-02-15 13:35:13
  • 2849

重排九宫格的代码

  • 2014年02月27日 08:41
  • 4KB
  • 下载

A*算法解决八数码(九宫重排)问题

问题描述 八数码-九宫重排问题作为一个经典的问题被大家所熟知,该问题是求解如何从开始的一个状态(布局)到达目标状态所需步数最少的问题。百度百科详情 问题分析 将每一个状态作为一个结点容易...
  • u014708761
  • u014708761
  • 2015-11-07 21:14:49
  • 2139

A*解决九宫格重排

  • 2011年11月12日 15:22
  • 8KB
  • 下载

九宫重排

问题描述(oj)   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。 经过若干次移动,可以形成第二个图所示的局面。  我们把第一...
  • newmemory
  • newmemory
  • 2016-03-09 21:45:40
  • 1476

蓝桥杯 历届试题-九宫重排

问题描述  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。   我们把第一个图的局...
  • turingwy
  • turingwy
  • 2016-02-19 22:31:56
  • 2229

A算法解九宫格

以前写拼图游戏的时候就有个疑问:如果随机生成每个图片的位置的话,这个拼图可能是永远也解不出来的。但是当时不知道如何去解一个九宫格问题。        最近了解了一下搜索算法,发现其实很多很多的问题都...
  • mazheng1989
  • mazheng1989
  • 2011-10-29 00:29:55
  • 4322

九宫重排---bfs

问题描述   如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。   我们把第一个图...
  • u012319493
  • u012319493
  • 2016-05-19 19:28:33
  • 2003
收藏助手
不良信息举报
您举报文章:深度优先、广度优先和A*算法实现的重排九宫问题
举报原因:
原因补充:

(最多只允许输入30个字)