八数码问题_启发搜索

#include<stdio.h>
#include<math.h>
typedef struct  
{
    long parent;
    long index;    
    int direction;//记录上一节点到当前节点空格移动方向
    int Grid[9];//存储局面
    int H;//启发函数值
}State;
State S,T;//起始态,目标态(目标态由评估函数决定好了)
State OPEN[2048];//队列-----待考察的状态
State CLOSE[2048];//--------考察过的状态
int OPhead=0,OPtail=0,openlen=2048;
int CLhead=0,CLtail=0,closelen=2048;

long INDEX=0;//记录下标
void readdata();
int search();
int Evaluate(State s);
State Swap(State v,int Epindex,int Nindex);//交换两个位置上的值
int Judge(State father,int n,int BlankIndex,int NumIndex);
void AI_Inspire();
void addtoopen(State v);//将节点v加到队列尾
State takeoutofopen();//取队列头数据
void addtoclose(State v);

int main()
{     
   readdata();//读取起始状态
   int flag=search();  
   int kk;
   if(flag==1)//找到了,输出CLOSE表中的考察过的状态
   {
      for(kk=CLhead;kk<CLtail;kk++)//输出从起点到终点的局面变化过程
      {  
           printf("第%d个状态: ",kk);
           for(int jj=0;jj<9;jj++)
               printf(" %d",CLOSE[kk].Grid[jj]);
           printf("    节点扩展下标: %d\n",CLOSE[kk].index);
      }
      printf("\n");

       /*int i,j,k;
       State Process[2000];
       State End=CLOSE[CLtail-1];//将终点棋局保存起来
       for(int ii=CLhead;ii<CLtail-1;ii++)//将考察过的节点按其下标进行排序---升序
       {
           int kk=ii;
           for(int jj=ii+1;jj<CLtail-1;jj++)
               if(CLOSE[jj].index <CLOSE[kk].index) 
                  kk=jj;               
           State temp=CLOSE[ii];
           CLOSE[ii]=CLOSE[kk];
           CLOSE[kk]=temp;
       }            
       int k=0;
       Process[k++]=End;//取从终点到起点的节点
       for(int i=CLtail-2;i>=CLhead;i--)
       {
           if(End.parent ==CLOSE[i].index)
           {
                Process[k++]=CLOSE[i];
                End=CLOSE[i];
           }         
       }
      for(j=k-1;j>=0;j--)//输出从起点到终点的局面变化过程
      {  
           printf("第%d个状态: ",k-1-j);
           for(int jj=0;jj<9;jj++)
               printf(" %d",Process[j].Grid[jj]);
           printf("\n");
       }*/
   }
   else     
        printf("未找到\n");
   return 0;
}


int search()
{
    State father;    
    while(OPhead != OPtail)//OPEN[]表中还有待考察的数据
    {
       int BlankIndex,NumIndex;
       father = takeoutofopen();//从队列头取数据
       addtoclose(father);//将father节点加入CLOSE表(已考察)
       for(int k=0;k<9;k++)
          if(father.Grid[k]==0)
          {  BlankIndex=k; break;  } //记录父节点father空格位所在的位置      
       
       //////四个方向搜索//////    
       //空格向左移
       if(father.direction !=3)
       {
           NumIndex=BlankIndex/3*3+BlankIndex%3-1;       
           if(BlankIndex%3-1>=0)
           {        
               int flag=Judge(father,1,BlankIndex,NumIndex);
               if(flag==1) return 1;
           }
       }
       //空格向上移
       if(father.direction !=4)
       {
           NumIndex=(BlankIndex/3-1)*3+BlankIndex%3;//计算待移动的数据所在的位置
           if(BlankIndex/3-1>=0)
           {     
               int flag=Judge(father,2,BlankIndex,NumIndex);
               if(flag==1) return 1;       
           }
       }
       //空格向右移
       if(father.direction !=1)
       {
           NumIndex=BlankIndex/3*3+BlankIndex%3+1;       
           if(BlankIndex%3+1<3)
           {
               int flag=Judge(father,3,BlankIndex,NumIndex);
               if(flag==1) return 1; 
           }
       }
       //空格向下移
       if(father.direction !=2)
       {
           NumIndex=(BlankIndex/3+1)*3+BlankIndex%3;
           if(BlankIndex/3+1<3)
           {              
               int flag=Judge(father,4,BlankIndex,NumIndex);
               if(flag==1) return 1;  
           }
       }
 
       AI_Inspire();//调整OPEN标       
    }
    return 0;
}



void AI_Inspire()
{
       //按启发函数值对OPEN表中的元素进行排序----降序
       State temp[2048];
       int t=0;
       int ii,jj;
       //取出
       if(OPtail<OPhead)
       {   for(ii=OPhead;ii<2048;ii++) 
               temp[t++]=OPEN[ii];
           for(ii=0;ii<OPtail;ii++)
               temp[t++]=OPEN[ii];
       } else
       {
           for(ii=OPhead;ii<OPtail;ii++)
               temp[t++]=OPEN[ii];
       }     
       //排序
       for(ii=0;ii<t;ii++)
       {
           int kk=ii;
           for(jj=ii+1;jj<t;jj++)
               if(temp[jj].H >= temp[kk].H) //正确位码的个数大的放在队列的最前面,优先展开
                  kk=jj;               
           State tp=temp[ii];
           temp[ii]=temp[kk];
           temp[kk]=tp;
       }
       //printf("%d---",temp[0].H);//调试
       //放回
       t=0;
       if(OPtail<OPhead)
       {
           for(ii=OPhead;ii<2048;ii++) 
               OPEN[ii]=temp[t++];
           for(ii=0;ii<OPtail;ii++)
               OPEN[ii]=temp[t++];
       } else
       {
           for(ii=OPhead;ii<OPtail;ii++)
               OPEN[ii]=temp[t++];
       }   
      //printf("%d\n",OPEN[OPhead].H);//调试
}
int Judge(State father,int n,int BlankIndex,int NumIndex)
{
    State son;
    son.parent =father.index ;//1.子节点明确自己的父节点下标
    
    son.direction = n;
    for(int i=0;i<9;i++)
        son.Grid[i]=father.Grid[i];//3.子节点局面复制父节点局面
    son=Swap(son,BlankIndex,NumIndex);//3.son(f)->son
    son.H=Evaluate(son);//4.子节点的启发函数值

    if(son.H==T.H) 
    {       
        son.index =INDEX++; 
        addtoclose(son); 
        return 1; //表明找到了终点    
    }
    else 
    {   son.index =INDEX++;  //2.子节点自己的下标---father.index*4+n以指数形式增长,会超出long的范围(不能用)
        addtoopen(son);//将当前状态节点加入到OPEN表               
    }
    return 0;
}
void addtoopen(State v)
{
    OPEN[OPtail++]=v; //向尾部添加节点 
    OPtail = OPtail%openlen;
}
State takeoutofopen()//从队列头取节点数据
{
    State v;
    v=OPEN[OPhead++];//向头部取节点
    OPhead=OPhead%openlen;
    return v;
}
void addtoclose(State v)
{
    CLOSE[CLtail++]=v;    
    CLtail = CLtail%closelen;
}
//v为传入的局面,BlankIndex为空格位置,NumIndex为被交换的数据位置
State Swap(State son,int BlankIndex,int NumIndex)
{
    int temp=son.Grid[BlankIndex];//取空格位置的数字
    son.Grid[BlankIndex]=son.Grid[NumIndex];
    son.Grid[NumIndex]=temp;
    return son;//返回新局面
}

int Evaluate(State s)//启发式函数
{
   int count=0;//正确位码的个数
   for(int i=0;i<9;i++)
   {   
       if(s.Grid[i]==T.Grid[i] && s.Grid[i]!=0)
           count++;
   }
   return count;//返回逆序值
}
void readdata()
{
    int Arr[10]={8,7,6,5,4,3,2,1,0};
    int Brr[10]={0,1,2,3,4,5,6,7,8};

    //28步
    //终止局面
    T.index=-1;//1
    T.parent=-1;//2
    for(int i=0;i<9;i++)//4
        T.Grid[i]=Arr[i];    
    T.H=Evaluate(T);//5
    //起始局面
    S.index=INDEX++;
    S.parent=-1;
    for(i=0;i<9;i++)
        S.Grid[i]=Brr[i];
    S.H=Evaluate(S);//起始局面评估
    addtoopen(S); 
}

测例:

第0个状态:  0 1 2 3 4 5 6 7 8    节点扩展下标: 0
第1个状态:  3 1 2 0 4 5 6 7 8    节点扩展下标: 2
第2个状态:  3 1 2 6 4 5 0 7 8    节点扩展下标: 4
第3个状态:  3 1 2 6 4 5 7 0 8    节点扩展下标: 5
第4个状态:  3 1 2 6 4 5 7 8 0    节点扩展下标: 7
第5个状态:  3 1 2 6 4 0 7 8 5    节点扩展下标: 8
第6个状态:  3 1 0 6 4 2 7 8 5    节点扩展下标: 10
第7个状态:  3 0 1 6 4 2 7 8 5    节点扩展下标: 11
第8个状态:  0 3 1 6 4 2 7 8 5    节点扩展下标: 12
第9个状态:  6 3 1 0 4 2 7 8 5    节点扩展下标: 14
第10个状态:  6 3 1 7 4 2 0 8 5    节点扩展下标: 16
第11个状态:  6 3 1 7 4 2 8 0 5    节点扩展下标: 17
第12个状态:  6 3 1 7 4 2 8 5 0    节点扩展下标: 19
第13个状态:  6 3 1 7 4 0 8 5 2    节点扩展下标: 20
第14个状态:  6 3 0 7 4 1 8 5 2    节点扩展下标: 22
第15个状态:  6 0 3 7 4 1 8 5 2    节点扩展下标: 23
第16个状态:  0 6 3 7 4 1 8 5 2    节点扩展下标: 24
第17个状态:  7 6 3 0 4 1 8 5 2    节点扩展下标: 26
第18个状态:  7 6 3 8 4 1 0 5 2    节点扩展下标: 28
第19个状态:  7 6 3 8 4 1 5 0 2    节点扩展下标: 29
第20个状态:  7 6 3 8 4 1 5 2 0    节点扩展下标: 31
第21个状态:  7 6 3 8 4 0 5 2 1    节点扩展下标: 32
第22个状态:  7 6 0 8 4 3 5 2 1    节点扩展下标: 34
第23个状态:  7 0 6 8 4 3 5 2 1    节点扩展下标: 35
第24个状态:  0 7 6 8 4 3 5 2 1    节点扩展下标: 36
第25个状态:  8 7 6 0 4 3 5 2 1    节点扩展下标: 38
第26个状态:  8 7 6 5 4 3 0 2 1    节点扩展下标: 40
第27个状态:  8 7 6 5 4 3 2 0 1    节点扩展下标: 41
第28个状态:  8 7 6 5 4 3 2 1 0    节点扩展下标: 43

posted on 2012-10-16 19:23  IThinktan  阅读(367)  评论(0编辑  收藏  举报

导航