根据启发函数(A*算法)求解八数码问题


根据启发函数(A*算法)求解八数码问题

 

 

 

http://www.java3z.com/cwbwebhome/article/article5/5792.html?id=1414

    八数码方块移动游戏要求从一个含8个数字(用1-8表示)的方块以及一个空格方块(用0表示)的3x3矩阵的起始状态开始,不断移动该空格方块以使其和相邻的方 块互换,直至达到所定义的目标状态。空格方块在中间位置时有上、下、左、右4个方向可移动,在四个角落上有2个方向可移动,在其他位置上有3个方向可移 动。例如,假设一个3x3矩阵的初始状态为:
   8 0 3
   2 1 4
   7 6 5
目标状态为:
   1 2 3
   8 0 4
   7 6 5
则一个合法的移动路径为:

 
 
 8 0 3  8 1 3  8 1 3  0 1 3  1 0 3  1 2 3
 2 1 4> 2 0 4> 0 2 4 >8 2 4> 8 2 4> 8 0 4
 7 6 5 7 6 5 7 6 5 7 6 5 7 6 5 7 6 5
 


     另外,在所有可能的从初始状态到目标状态的移动路径中,步数最少的路径被称为最短路径;在上面的例子中,最短路径为5。如果不存在从初试状态到目标状态的任何路径,则称该组状态无解。

根据启发函数求解八数码问题
根据启发函数(A*算法)求解八数码问题 - 梦幻骑士 - 梦幻骑士

import java.applet.Applet;  import java.awt.*;  import java.awt.Graphics;  import java.util.Vector;  public class EightNumber extends Applet implements Runnable   {   /*内部类,表示一个节点,如    * 0  1  2    * 3  4  5    * 6  7  8    */   private class State   {    int[] states = new int[9];    int size;    int steps;    public State(int [] s)    {     int i;     for(i=0;i<9;i++)      states[i] = s[i];    }    public boolean equals(State st)    {     int[] s=st.getStates();     int i;     for(i=0;i<9;i++)      if(s[i] != states[i])       return false;     return true;    }   //返回从当前节点跳到下一节点时,与“0”交换移动的位置,这个位置的数字用红色画出    public int judgeMove(State st)    {     int[] s=st.getStates();     int i;     for(i=0;i<9;i++)     {      if(s[i] != states[i] && s[i]!=0)       return i;     }     return -1;    }    public int[] getStates()    {     return states;    }    public int expandSize()//返回从一个节点出发,可以扩展的点节数(以“0”为中心)    {     if(states[4] == 0)//如果"0"位于中心,可以扩展出4个节点      size = 4;     else if(states[0]==0 || states[2]==0 || states[6]==0 || states[8]==0)      size = 2;//如果“0”位于角上,可以扩展出2个节点     else      size = 3;//边上     return size;    }    public State[] expandState()//返回当前节点扩展出的所有节点    {     State[] st;     int [] ex=new int[9];     int i,j,k;     int m=0,n=0;     int a=0,b=0;     st = new State[size];     for(i=0;i<3;i++)     {      for(j=0;j<3;j++)      {       k = i*3+j;       ex[k] = states[k];       if(states[k] == 0)//记录“0”的位置       {        m = i;        n = j;       }      }     }     //以下根据"0"的位置,求出所有扩展的节点     i = 0;     a = m*3+n;     if(m-1>=0)     {      b = (m-1)*3+n;      ex[a] = ex[b];      ex[b] = 0;      st[i] = new State(ex);      ex[b] = ex[a];      ex[a] = 0;      i++;     }     if(m+1<=2)     {      b = (m+1)*3+n;      ex[a] = ex[b];      ex[b] = 0;      st[i] = new State(ex);      ex[b] = ex[a];      ex[a] = 0;      i++;     }     if(n-1>=0)     {      b = m*3+(n-1);      ex[a] = ex[b];      ex[b] = 0;      st[i] = new State(ex);      ex[b] = ex[a];      ex[a] = 0;      i++;     }     if(n+1<=2)     {      b = m*3+(n+1);      ex[a] = ex[b];      ex[b] = 0;      st[i] = new State(ex);      ex[b] = ex[a];      ex[a] = 0;      i++;     }     return st;    }   }   Image[] stateImg = new Image[10];   Image[] moveImg = new Image[10];   Image stepsImg;   Vector vecClose = new Vector();//闭集,记录下已经扩展的节点   Vector vecOpen = new Vector();//开集,记录下未扩展的节点   int[] first = {7,2,4,5,0,6,8,3,1};   int[] aim = {0,1,2,3,4,5,6,7,8};   State nowState = null;//当前节点   State aimState = new State(aim);//目标节点   int stepX;   int stepY;   int startX;   int startY;   int steps;   int move;   boolean start;   Thread moveTh = null;   public void init()    {    int i;    Integer tmp;    String fileName;     State st = new State(first);    st.steps = 0;        resize(200,300);    startX = 16;    startY = 19;    stepX = 55;    stepY = 55;    steps = 0;    start = false;    move = -1;    for(i=0;i<10;i++)    {     tmp = new Integer(i);     fileName = "img/";     fileName = fileName + tmp.toString()+"_1.jpg";     stateImg[i] = getImage(getCodeBase(),fileName);     waitForImage(stateImg[i]);     fileName = "img/";     fileName = fileName + tmp.toString() + "_2.jpg";     moveImg[i] = getImage(getCodeBase(),fileName);     waitForImage(stepsImg);    }    vecOpen.add(st);//将首节点加入到开集中    fileName = "img/steps.jpg";    stepsImg = getImage(getCodeBase(),"img/steps.jpg");    waitForImage(stepsImg);        }      public void waitForImage(Image i)//载入图像     {      MediaTracker tracker = new MediaTracker(this);          try          {           tracker.addImage(i,0);              tracker.waitForID(0);          }          catch(InterruptedException e) {System.err.println("Wait interrupted.");}     }      public void paint(Graphics g) //画当前节点   {    int i,j,k;    int[] state;    Integer tmp;    if(start == false)     return ;    state = nowState.getStates();    g.drawImage(stepsImg,startX+20,startY,this);    tmp = new Integer(steps);    g.drawString("第"+tmp.toString()+"步",startX+80,startY+20);        for(i=0;i<3;i++)    {     for(j=0;j<3;j++)     {      k = i*3+j;            if(move == k)      {       putNumber(g,state[k],i,j,false);//刚移动的位置,用红色画出      }      else      {       putNumber(g,state[k],i,j,true);      }     }    }   }   public void update(Graphics g)   {    paint(g);  }   private void putNumber(Graphics g,int number,int i,int j,boolean isState )   {    int x,y;    x = startX + j*stepX;    y = startY + i*stepY + stepY;    if(isState)    {     g.drawImage(stateImg[number],x,y,this);    }    else    {     g.drawImage(moveImg[number],x,y,this);    }   }   //启发函数,计算节点st与目标节点的距离(曼哈顿距离)。   private int suggestFunc(State st)   {    int i,j,m,n;    int a=0,b=0;    int result=0;    int[] state;    state = st.getStates();    for(i=0;i< 3;i++)    {     for(j=0;j< 3;j++)     {      a = i*3+j;      if(state[a]==0)       continue;      for(m=0;m< 3;m++)      {       for(n=0;n< 3;n++)       {        b = m*3+n;        if(state[a] == aim[b])        {         result += (Math.abs(m-i)+Math.abs(n-j));         break;        }       }       if(state[a] == aim[b])        break;      }     }    }    return result;   }      public void start()   {    if(moveTh == null)    {     moveTh = new Thread(this);     moveTh.start();//启动线程    }   }   public void stop()   {    if(moveTh != null)    {     moveTh = null;    }   }   public void run()   {       searchPath();   }      //寻找路径   private boolean searchPath()   {    int openSize;    State st;    boolean result=false;    start = true;    while(!vecOpen.isEmpty())    {     openSize = vecOpen.size();;     st = (State)vecOpen.elementAt(openSize-1);     if(nowState != null)     {      move = nowState.judgeMove(st);     }          nowState = st;     vecOpen.remove(openSize-1);     vecClose.add(nowState);     if(expandNowState() == 0)     {      result = true;     }     steps++;     repaint();     if(result == true)      break;     try     {      Thread.sleep(2000);     }     catch(InterruptedException e){}         }    return result;   }      private boolean haveContained(State st)//判断闭集中是否包含节点st   {    int size;    int i;    State tmp;    size = vecClose.size();    for(i=0;i< size;i++)    {     tmp = (State)vecClose.elementAt(i);     if(tmp.equals(st))      return true;    }    return false;   }   //扩展当前节点,1表示扩展成功,0表示找到目标节点,-1表示当前节点不可扩展   private int expandNowState()   {    int[] value = {255,255,255,255};    int size;    int i,j;    int have = -1;    State st[];    State tmpState;    int tmp;    size = nowState.expandSize();//当前节点能扩展的节点数    st = nowState.expandState();//获取所有扩展的节点    for(i=0;i< size;i++)    {     if(!haveContained(st[i]))     {      value[i] = suggestFunc(st[i]);      if(value[i] == 0)      {       move = nowState.judgeMove(st[i]);       nowState = st[i];       return 0;      }      else        have = 1;     }    }    if(have == 1)//对扩展的节点根据距离排序    {     for(i=0;i< size;i++)     {      for(j=i+1;j< size;j++)      {       if(value[j]>value[i])       {        tmp = value[j];        tmpState = st[j];        value[j] = value[i];        st[j] = st[i];        value[i] = tmp;        st[i] = tmpState;       }      }     }     for(i=0;i< size;i++)     {      if(value[i]!=255)      {       vecOpen.add(st[i]);//所有扩展的节点排序后放入开集      }     }    }    return have;   }  }                    


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值