八数码问题的A*算法实现

问题描述

八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。

代码实现

/*
AIDreamer
2017/5/27
*/
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
using namespace std;
const int MAXNODE=100000;
const int INF=999999999;
const int MOD=10007;
struct NODE
{
     int state;
     int blank;//blank表示0在state的第几位数字之后
     int f;//估价函数
     int g;//从起始节点到目前的步数
     int h;//启发式函数,目前节点和目标节点之间的距离,用欧几里得距离计算
     int pre;//该节点的父亲节点

     int loc;
     bool operator < (const NODE &rhs)const {
          return f>rhs.f;
      }
}node[MAXNODE];
bool CLOSE[MAXNODE];
int nodecount=0;

//hash表用来保存访问过的状态
struct HASH
{
     int state[100];//下标从1开始,保存状态
     int state_loc[100];//保存状态所对应的下标
     int cnt;
}Hash[MAXNODE];
void Put_into_hash(int x)//将node[x]存到hash表中
{
      int loc=node[x].state%MOD;
      Hash[loc].state[++Hash[loc].cnt]=node[x].state;
      Hash[loc].state[Hash[loc].cnt]=x;
}
int  Is_in_hash(struct NODE a)//若在hash表中返回状态在node中的下标,若不在返回-1
{
      int loc=a.state%MOD;
      for(int i=1;i<=Hash[loc].cnt;i++)
      {
            if(a.state==Hash[loc].state[i])return Hash[loc].state_loc[i];
      }
      return -1;
}

NODE init_node;
NODE target_node;

/*
得到起点和终点的state
*/
void In()
{
    int a[10];//保存3*3的格子
    int state=0;
    int blank;
    int ans,t;
    //得到init_node
    ans=0;
    for(int i=0;i<9;i++)
    {
        scanf("%d",&t);
        if(t==0){init_node.blank=i;continue;}
        ans=ans*10+t;
    }
    init_node.state=ans;

    //得到target_node
    ans=0;
    for(int i=0;i<9;i++)
    {
        scanf("%d",&t);
        if(t==0){target_node.blank=i;continue;}
        ans=ans*10+t;
    }
    target_node.state=ans;
}

int Get_euclidean_distance(struct NODE aa,struct NODE bb)
{
      //先将int型的状态转换到数组中
      int a[10];
      int b[10];
      int a_state=aa.state;
      int b_state=bb.state;
      for(int i=8;i>=0;i--)
      {
          if(aa.blank==i){a[i]=0;continue;}
          a[i]=a_state%10;
          a_state/=10;
      }
      for(int i=8;i>=0;i--)
      {
          if(bb.blank==i){b[i]=0;continue;}
          b[i]=b_state%10;
          b_state/=10;
      }
      //计算两个状态之间的距离
      int sum_dis=0;
      int t;//临时变量
      for(int i=0;i<9;i++)
      {
            for(int j=0;j<9;j++)
            {
                if(a[i]==b[j] && a[i]!=0)
                {
                    t=abs(i-j);
                    sum_dis+=t%3+t/3;
                }
            }
      }
      return sum_dis;
}

void Init()
{
      init_node.g=0;
      init_node.h=Get_euclidean_distance(init_node,target_node);
      init_node.f=init_node.g+init_node.h;
      init_node.pre=0;

      target_node.f=INF;
      target_node.pre=0;
}

void Change_state(struct NODE &node,int blank_loc,int num_loc)//改变node的状态,将状态中blank_loc和num_loc的值互换
{
      int s[10];
      int node_state=node.state;
      for(int i=8;i>=0;i--)
      {
          if(node.blank==i){s[i]=0;continue;}
          s[i]=node_state%10;
          node_state/=10;
      }
      s[blank_loc]=s[num_loc];
      s[num_loc]=0;
      node.blank=num_loc;
      node.state=0;
      for(int i=0;i<9;i++)
      {
           if(s[i]!=0)node.state=node.state*10+s[i];
      }

      return ;
}
void Exchange_state(struct NODE &node1,struct NODE &node2)//交换node1状态和node2状态
{
      struct NODE temp_node;
      temp_node=node1;
      node1=node2;
      node2=temp_node;
}
void Print_node(struct NODE x)//将状态以3*3的形式输出
{
      int state=x.state;
      int blank=x.blank;
      int s[10];
      for(int i=8;i>=0;i--)
      {
            if(i==blank){s[i]=0;continue;}
            s[i]=state%10;
            state/=10;
      }
      for(int i=0;i<9;i++)
      {
            cout<<s[i]<<" ";
            if(i%3==2)cout<<endl;

      }
}

void A_Star()//找到最优方案后更新target_node中的pre值
{
    node[++nodecount]=init_node;
    node[nodecount].loc=1;
    priority_queue<NODE> Q;
    Q.push(node[1]);//将初始状态入队
    Put_into_hash(1);
    while(!Q.empty())
    {

        struct NODE x=Q.top();
        if(x.state==target_node.state && x.blank==target_node.blank){ target_node=x;break;}
        Q.pop();
        NODE temp=x;//临时结构体变量
        for(int i=0;i<9;i++)
        {
              temp=x;
              if(    (abs(temp.blank-i)/3+abs(temp.blank-i)%3) ==1 )
              {
                    Change_state(temp,temp.blank,i);
                    //cout<<"after_change: "<<temp.state<<" "<<temp.blank<<endl;
                    temp.g=x.g+1;
                    temp.h=Get_euclidean_distance(temp,target_node);
                    temp.f=temp.g+temp.h;
                    int loc=Is_in_hash(temp);
                    if(loc==-1)//若不在hash表中则加入到hash表
                    {
                        node[++nodecount]=temp;
                        node[nodecount].loc=nodecount;
                        Put_into_hash(nodecount);
                        node[nodecount].pre=x.loc;
                        Q.push(node[nodecount]);
                    }
                    else
                    {
                        if(CLOSE[loc]!=1)//在OPEN表中
                        {
                            if(temp.f<node[loc].f)
                            {
                                  node[loc].f=temp.f;node[loc].g=temp.g;node[loc].h=temp.h;
                                  node[loc].pre=x.loc;
                            }
                        }
                        else  //节点在CLOSE表中
                        {
                            if(temp.f<node[loc].f)
                            {
                                node[loc].f=temp.f;node[loc].g=temp.g;node[loc].h=temp.h;
                                node[loc].pre=x.loc;
                                Q.push(node[loc]);//将该节点加入到OPEN表中
                                CLOSE[loc]=0;
                            }
                        }
                    }
              }
        }
        CLOSE[x.loc]=1;
    }
}

int main()
{
    In();
    //Exchange_state(init_node,target_node);//为了方面最后输出,交换初始和目标状态
    Init();
    cout<<"初始状态: "<<init_node.state<<" 空格位置: "<<init_node.blank<<endl;
    cout<<"目标状态: "<<target_node.state<<" 空格位置: "<<target_node.blank<<endl;


    A_Star();
    int loc=target_node.loc;
    int step=0;
    while(loc!=0)
    {
          cout<<"----------第"<<step++<<"步:----------"<<endl;
          Print_node(node[loc]);
          loc=node[loc].pre;
    }
    cout<<endl;
    cout<<"一共需要"<<step-1<<"步!"<<endl;
    return 0;
}
/*
1 0 3
7 2 4
6 8 5

1 2 3
8 0 4
7 6 5
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值