8数码问题, poj1009

主要使用了A*搜索和hash函数


#include<iostream>

#include<stdlib.h>
using namespace std;


typedef struct Direction{
       char pre;//前一节点到后一节点的移动方向 
       Direction *prior;
}Direction;
typedef struct State{
       int no[9];//数字序列
       int space;//空格位置
       int steps;//到达该状态是已走过的步数
       int f;//估价函数值 
       State *next;
       Direction *dir; 
}State;
bool flag[700000];//节点hash表,每一个节点的状态,true 表示该节点已遍历
int dest[]={8,0,1,2,3,4,5,6,7};//dest[i]表示数字i的目标位置 
int fac[10];//阶乘序列 
char direct[4]={'u','d','l','r'};     
       


int expect(int *no)//启发函数 
{    
     int h=0;
     for(int i=0;i<9;++i)
        h+=abs(i/3-dest[no[i]]/3)+abs(i%3-dest[no[i]]%3);
     return h;
}


int hash(int *no)//hash函数 
{
    int h=0;
    for(int i=8;i>=0;--i)
    {
         int count=0;
         for(int j=8;j>i;--j)
            if(no[j]<no[i])
               count++;
         h+= count*fac[8-i];      
    }        
    
    return h;

void print(Direction *dir)//输出方向,逆向输出 
{
     if(dir->prior)
         print(dir->prior);
     cout<<dir->pre;    
}
bool produce(State *res,State *&des,int i)//生成新节点,i表示方向 
{
     int row=res->space/3;
     int col=res->space%3;
     int row_n,col_n;
     switch(i)
     {
     case 0:
            if(row<=0) return false;
            row_n=row-1;
            col_n=col;
            break;
                    
     case 1:
            if(row>=2) return false;
            row_n=row+1;
            col_n=col;
            break;
            
     case 2:
            if(col<=0) return false;
            row_n=row;
            col_n=col-1;
            break;
            
     case 3:
            if(col>=2) return false;
            row_n=row;
            col_n=col+1;
            break;
            
     default:return false;
     }
     des=(State *)malloc(sizeof(State));
     for(int j=0;j<9;++j)
        des->no[j]=res->no[j];
     des->no[row*3+col]=des->no[row_n*3+col_n];
     des->no[row_n*3+col_n]=0; 
     des->space=row_n*3+col_n;
     des->steps=res->steps+1;
     des->f=des->steps+expect(des->no);
     des->dir=(Direction *)malloc(sizeof(Direction));
     des->dir->pre=direct[i];
     des->dir->prior=res->dir;            
     return true;
     
     
}


int main()
{
    fac[0]=1;
    char ch;
    for(int i=1;i<10;++i)
       fac[i]=fac[i-1]*i;   
    State *start=(State *)malloc(sizeof(State));
    State *open=(State *)malloc(sizeof(State));//用于存放新生成的节点 
    for(int i=0;i<9;++i)
    {
        cin>>ch;
        if(ch=='x')
        {
            start->no[i]=0;
            start->space = i;           
        }        
        else start->no[i]=(int )(ch-'0');
    }
    start->steps=0;
    start->f=start->steps+expect(start->no);
    start->next=NULL;
    start->dir=NULL;    
    open->next=start;
    //对flag表进行初始化
    for(int i=0;i<fac[9];++i)
       flag[i]=false;
    while(open->next)
    {
         State *op=open->next;//当前待操作节点
         if(op->f==op->steps)
         {
             print(op->dir);
             cout<<endl;
             getchar();
             return 0;                     
         }  
         //生成新节点 0123分别对应于上下左右 
         open->next=op->next;
         for(int i=0;i<4;++i)
         {
              State *node;
              if(produce(op,node,i)&&!flag[hash(node->no)])
              {
                   State *temp_node=open;
                   while(temp_node->next && (temp_node->next->f < node->f))//将新节点按估价值顺序插入open 
                       temp_node=temp_node->next;    
                   node->next=temp_node->next;
                   temp_node->next=node;    
              }      
               
         }   
         flag[hash(op->no)]=true;
         free(op);            
    }        
    cout<<"unsolvable"<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值