八数码难题---启发式搜素java
1.启发式搜索:node
特色:重排OPEN表,选择最有但愿的节点加以扩展算法
种类:有序搜索(A算法)、A*算法等数据结构
2.估价函数ide
用来估算节点处于最佳求解路径上的但愿程度的函数函数
f(n) = g(n) + h(n)this
n——搜索图中的某个当前被扩展的节点;设计
f(n) ——从初始状态节点s, 经由节点n到达目标节点ng,估计的最小路径代价; code
g(n) ——从s到n 的实际路径代价;rem
h(n)——从n到ng,估计的最小路径代价。
八数码难题估价函数:f(n)=d(n)+w(n)
其中:d(n)为n的深度 w(n)为不在位的棋子数
3.有序搜索:
选择OPEN表上具备最小f值的节点做为下一个要扩展的节点。
八数码难题使用全局择优搜索:
选择OPEN表上具备最小f值的节点做为下一个要扩展的节点,即老是选择最有但愿的节点做为下一个要扩展的节点。
在八数码难题中, 令估价函数
f(n)=d(n)+p(n)
启发函数h(n)=p(n),p(n)为不在位的棋子与其目标位置的距离之和,则有p(n)≤h*(n),知足A*算法的限制条件。
w(n)——不在位的棋子数,不够贴切,错误选用节点加以扩展。
p(n)——更接近于h*(n)的h(n),其值是节点n与目标状态节点相比较,每一个错位棋子在假设不受阻拦的状况下,移动到目标状态相应位置所需走步的总和。
p(n)比w(n)更接近于h*(n),由于p(n)不只考虑了错位因素,还考虑了错位的距离(移动次数)
数据结构的创建:因为open,close表常设计删除增长节点的操做,故使用单链表最好
open表存储生成的节点且未被处理的节点,处理过的节点取出放入close表
close表存储处理过的节点
status表存储全部生成的节点
采用全局择优的思想
java代码以下:
package 八数码难题; import java.util.Collections; import java.util.LinkedList; import java.util.List; public class Main { static int f[][]=new int[3][3]; static int e[][]=new int[3][3]; static int p=0; static int dir[][]={{0,1},{1,0},{0,-1},{-1,0}}; static List<node>openlist=new LinkedList<node>(); static List<node>closelist=new LinkedList<node>(); static int d=0; static List<node>status=new LinkedList<node>(); public static void main(String[] args) { // TODO Auto-generated method stub String str1;//初始状态 String str2;//目标状态 str1="2831647.5";//空格用.表示 str2="1238.4765"; for(int i=0;i<str1.length();i++){ f[i/3][i-i/3*3]=str1.charAt(i)=='.'?0:str1.charAt(i)-'0'; e[i/3][i-i/3*3]=str2.charAt(i)=='.'?0:str2.charAt(i)-'0'; } node f1=new node(f,d,e); openlist.add(f1); status.add(f1); Search();//寻找最短路径 toPrint();//输出状态空间 } public static boolean check(int x,int y){ if(x<0||x>=3||y<0||y>=3){ return false; } return true; } public static boolean contains(List<node> list,int a[][]){ int flag=0; int a1[][] = new int[3][3]; for(int i=0;i<list.size();i++){ flag=0; for(int j=0;j<3;j++){ a1[j]=list.get(i).a[j].clone(); for(int k=0;k<3;k++){ if(a1[j][k]==a[j][k]){ flag++; } } } if(flag==9) return false; } return true; } //输出状态空间 public static void toPrint(){ int a[][]; System.out.println(); System.out.println("========状态空间大小为:"+status.size()+"-----"); int k1=0,i=0; while(i<status.size()){ a=status.get(i).a; System.out.println("---------------"); for(int j=0;j<3;j++){ for(int k=0;k<3;k++){ System.out.print(a[j][k]+" "); } System.out.println(); } i++; } } public static void Search(){ hnode ehn=new hnode(e); while(!openlist.isEmpty()){ int at[][]=new int[3][3]; int min=0; for(int i=0;i<openlist.size();i++){ if(openlist.get(i).f<openlist.get(min).f){ min=i; } } node n=null; n=openlist.remove(min); closelist.add(n); for(int i=0;i<3;i++){ at[i]=n.a[i].clone(); } int x = 0,y = 0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(at[i][j]==p){ x=i;y=j;//记录空格在棋盘中的位置(原) break; } } } for(int i=0;i<4;i++){ int nx,ny,t; nx=x+dir[i][0];//空格移动的位置(现) ny=y+dir[i][1]; if(check(nx,ny)){ t=at[nx][ny]; at[nx][ny]=at[x][y]; at[x][y]=t; d=n.h+1; hnode thn=new hnode(at); node tn=new node(at,d,e); if(thn.equals(ehn)){ //找到最短路径 status.add(tn); closelist.add(tn); toOutput(); return; } if(contains(openlist,at)&&contains(closelist,at)){ openlist.add(tn); status.add(tn); } t=at[nx][ny]; at[nx][ny]=at[x][y]; at[x][y]=t; } } } return; } public static void toOutput(){ System.out.println("====移动路径以下===="); System.out.println("所需步数为:"+d); for(int i=0;i<closelist.size();i++){ int a[][]=closelist.get(i).a; System.out.println("----------------------"); for(int j=0;j<3;j++){ for(int k=0;k<3;k++){ System.out.print(a[j][k]+" "); } System.out.println(); } } } } class hnode{ //hash用于hashSet int hash; public hnode(){ } public hnode(int a[][]){ int hc=0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ hc*=10; hc+=a[i][j]; } } this.hash=hc; } public boolean equals(Object object){ hnode thn=(hnode)object; return thn.hash==hash; } @Override public int hashCode(){ return hash; } } class node{ int a[][];//九宫格的状态 int h;//深度 int f;//从初始状态节点s, 经由节点n到达目标节点ng,估计的最小路径代价 int p;//不在位的棋子与其目标位置的距离之和 public node(int [][]a,int h,int [][]e){ this.a=new int[3][]; for(int i=0;i<3;i++){ this.a[i]=a[i].clone(); } this.h=h; this.p=work(e); this.f=this.h+this.p; } public int work(int e[][]){ int ants=0; for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(a[i][j]!=e[i][j]&&a[i][j]!=0){ int r=0,c = 0,flag=0; for(int k=0;k<3;k++){ for(int k1=0;k1<3;k1++){ if(a[i][j]==e[k][k1]){ r=k; c=k1; ants+=Math.abs(r-i); ants+=Math.abs(c-j); flag=1; break; } } if(flag==1) break; } } } } return ants; } }