隐式图搜索(A*算法)————代码实现
一、九宫格对象
内容概述:
将九宫格每次移动后的结果看做一个对象,所以Square对象应该具有以下属性:
1:parent对象,用于存储当前图的上一步图的内容。
2:now_position [3][3],用于存储当前九宫格图中每个格子中的数。
g 表示当前结果对象已经移动的次数。(在状态空间中从初始节点到n节点的实际代价)。
h表示当前对象与目标结果,九宫格中内容不同的格子数。(当前对象的估计代价)
代码如下:
package ce;
public class Square {
public int [][]now_position=new int [3][3];
public Square up;
public Square down;
public Square left;
public Square right;
public Square parent;
public int g;//层数
public int h;
public Square(int a[][],Square parent,int h){
for(int r=0;r<3;r++) {
for(int r1=0;r1<3;r1++){
now_position[r][r1]=a[r][r1];
}
}
this.g =h;
this.parent=parent;
}
public int returnFx(){
return (h + g);
}
public void setGx(int g){
this.h =g;
}
}
返回当前状态的F(x)
public int returnFx()
设置当前状态的G(x)
public void setGx(int g)
二、A* 算法的实现
内容概述:
1.A_star_中定义的属性
1:int[][]start_position;定义一个数组用于存储九宫格初始时各个数字的位置
2:int [][]end_position;定义一个数组用于存储九宫格的目标状态
3:List queue;定义一个List集合作为队列,对每一步中的九宫格状态进行存储。
4:List parents;定义一个List集合,存储九宫格已经移动过的步骤,
5:List path;定义一个List集合,存储九宫格从初始状态移动到目标状态时的路径。
6. 调用Judgefeasible()判断当前的九宫格状态是否能达到目标状态。如果不能,就打印输出。
2.A_star算法的内容
:
内容概述:
1:对当前的九宫格状态假设移动,将移动后合法的九宫格状态加入队列,将队列按代价从小到大排列。选择代价最小的九宫格状态,并让其出队,继续重复模拟九宫格中的格子移动,直到达到目标状态。
2:获得目标状态的结果对象以后,将目标状态往回找父节点,添加到path中。
代码如下:
public void A_star() {
Square p = start_Quare;
queue.add(p);
while (!is_same(p, end_Quare)) {
int y= find_minfx(queue);
p = queue.get(y);
addSquare(p);
queue.remove(y);
}
q = p;//最后的目标格子位置
print();
}
3.模拟九宫格格子移动
内容概述:
1:模拟格子移动的过程中一共有四种情况,分别是向左移动,向上移动,向下移动,向右移动。
2:考虑到四种情况后,分别对四种情况中坐标移动后合法的情况创建对象,修改状态后将其入队。
代码如下:
public void addSquare(Square df){
int tmp;
Square p;
int [][]a=new int[3][3];
int [][]b=new int[3][3];
int [][]c=new int[3][3];
int [][]d=new int[3][3];
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++){
a[i][j]=df.now_position[i][j];
b[i][j]=df.now_position[i][j];
c[i][j]=df.now_position[i][j];
d[i][j]=df.now_position[i][j];
}
}
int x=0,y=0;
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++){
if(a[i][j]==0)
{
x=i;
y=j;//寻找空格的位置
}
}
}
if ((x - 1) >= 0)//假设左移
{
tmp=a[x][y];
a[x][y]=a[x-1][y];
a[x-1][y]=tmp;
p = new Square(a,null,0);
if (Judge_has_passed(parents,p))
{
p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
if (x + 1 <= 2)//假设右移
{
tmp=b[x][y];
b[x][y]=b[x+1][y];
b[x+1][y]=tmp;
p = new Square(b,null,0);
if (Judge_has_passed(parents,p))
{
p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
if (y - 1 >= 0)//假设下移
{
tmp=c[x][y];
c[x][y]=c[x][y-1];
c[x][y-1]=tmp;
p = new Square(c,null,0);
if (Judge_has_passed(parents,p))
{ p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
if (y + 1 <= 2)
{
tmp=d[x][y];
d[x][y]=d[x][y+1];
d[x][y+1]=tmp;
p = new Square(d,null,0);
if (Judge_has_passed(parents,p))
{
p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
}
4.实现主要功能的函数
1.计算当前状态与目标状态,九宫格不同格子的数量。
public int unsameNum(Square p, Square q1)
2.判断当前状态是否可以达到目标状态。
public boolean Judge_feasible(Square start,Square end)
3.挑选价值最小的对象并返回下标
public int find_minfx(List<Square> list)
4.判断两个对象的九宫格中的内容是否相同
public boolean is_same(Square s1,Square s2)
5.展示输出实现九宫格寻路的时的步骤和状态。
public void print()
代码如下:
package ce;
public class Square {
public int [][]now_position=new int [3][3];
public Square up;
public Square down;
public Square left;
public Square right;
public Square parent;
public int g;//层数
public int h;
public Square(int a[][],Square parent,int h){
for(int r=0;r<3;r++) {
for(int r1=0;r1<3;r1++){
now_position[r][r1]=a[r][r1];
}
}
this.g =h;
this.parent=parent;
}
public int returnFx(){
return (h + g);
}
public void setGx(int g){
this.h =g;
}
}
package ce;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class A_star_ {
private int[][]start_position=new int [3][3];
private int [][]end_position=new int [3][3];
private List<Square> queue=new ArrayList<>();
private List<Square> parents=new ArrayList<>();
private List<Square> path =new ArrayList<>();
private Square start_Quare;
private Square end_Quare;
private long startTime;
private long endTime;
private Square q;
Scanner sc=new Scanner(System.in);
public A_star_(){
System.out.println("请输入九宫格的起始状态(空格用0代替):");
for(int i=0;i<3;i++){
start_position[i][0]=sc.nextInt();
start_position[i][1]=sc.nextInt();
start_position[i][2]=sc.nextInt();
}
System.out.println("请输入九宫格的最终状态:");
for(int i=0;i<3;i++){
end_position[i][0]=sc.nextInt();
end_position[i][1]=sc.nextInt();
end_position[i][2]=sc.nextInt();
}
startTime=System.currentTimeMillis();
start_Quare=new Square(start_position,null,0);
end_Quare=new Square(end_position,null,0);
if (Judge_feasible(start_Quare, end_Quare)) {//如果可行
A_star();
}else{
System.out.println("这两个九宫格直接无法通过移动空格实现转换");
}
}
public void A_star() {
Square p = start_Quare;
queue.add(p);
while (!is_same(p, end_Quare)) {
int y= find_minfx(queue);
p = queue.get(y);
addSquare(p);
queue.remove(y);
}
q = p;//最后的目标格子位置
print();
}
public void addSquare(Square df){
int tmp;
Square p;
int [][]a=new int[3][3];
int [][]b=new int[3][3];
int [][]c=new int[3][3];
int [][]d=new int[3][3];
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++){
a[i][j]=df.now_position[i][j];
b[i][j]=df.now_position[i][j];
c[i][j]=df.now_position[i][j];
d[i][j]=df.now_position[i][j];
}
}
int x=0,y=0;
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++){
if(a[i][j]==0)
{
x=i;
y=j;//寻找空格的位置
}
}
}
if ((x - 1) >= 0)//假设左移
{
tmp=a[x][y];
a[x][y]=a[x-1][y];
a[x-1][y]=tmp;
p = new Square(a,null,0);
if (Judge_has_passed(parents,p))
{
p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
if (x + 1 <= 2)//假设右移
{
tmp=b[x][y];
b[x][y]=b[x+1][y];
b[x+1][y]=tmp;
p = new Square(b,null,0);
if (Judge_has_passed(parents,p))
{
p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
if (y - 1 >= 0)//假设下移
{
tmp=c[x][y];
c[x][y]=c[x][y-1];
c[x][y-1]=tmp;
p = new Square(c,null,0);
if (Judge_has_passed(parents,p))
{ p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
if (y + 1 <= 2)
{
tmp=d[x][y];
d[x][y]=d[x][y+1];
d[x][y+1]=tmp;
p = new Square(d,null,0);
if (Judge_has_passed(parents,p))
{
p.parent=df;
p.g =df.g +1;
int count= unsameNum(p,end_Quare);
p.setGx(count);
queue.add(p);
parents.add(p);
}
}
}
public int unsameNum(Square p, Square q1){
int count=0;
for (int i = 0; i < 3; i++)
{ for (int j = 0; j < 3; j++)
{ if(p.now_position[i][j]!=q1.now_position[i][j])
{ count++; }
} }
return count;
}
public boolean Judge_has_passed(List<Square> q,Square s) {
int f=0;
boolean flag=false;
for (Square d : q) {
for (int a = 0; a < 3; a++) {
for (int a1 = 0; a1 < 3; a1++) {
if(d.now_position[a][a1]!=s.now_position[a][a1]){
f++;
flag=true;
break; } }
if(flag==true){
break; }
}
flag=false; }
if(f==q.size()){
return true;
} else{
return false; }
}
public boolean Judge_feasible(Square start,Square end){
int []b1=new int[9];
int []b2=new int[9];
int s11=0;
int s12=0;
int n1=0;
int n2=0;
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++){
b1[n1++]=start.now_position[i][j];
b2[n2++]=end.now_position[i][j];
}
}
for(int i=0;i<9;i++){
for(int j=0;j<i;j++){
if(b1[j]>b1[i]&&b1[j]!=0&&b1[i]!=0)
{ s11++;}
}
}
for(int i=0;i<9;i++){
for(int j=0;j<i;j++){
if(b2[j]>b2[i]&&b2[j]!=0&&b2[i]!=0)
s12++;
}
}
if(s11%2==s12%2)
return true;
else
return false;
}
public int find_minfx(List<Square> list){
int i=0;
int h=list.get(0).returnFx();
for(int i1=0;i1<list.size();i1++){
if(list.get(i1).returnFx()<h){
h=list.get(i1).returnFx();
i=i1;
}
}
return i;
}
public void print(){
Square q1=q;
while (q1 != null) {
path.add(q1);
q1 = q1.parent;
}
System.out.println("九宫格排列中移动的步骤为:");
for(int k=path.size()-1;k>=0;k--)
{
System.out.println("第"+(path.size()-k-1)+"步为:");
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++){
System.out.print(path.get(k).now_position[i][j]+" ");
}
System.out.println();
}
}
endTime=System.currentTimeMillis();
System.out.println("总程序运行时间: "+(endTime-startTime)/1000.0+"s");
}
public boolean is_same(Square s1,Square s2){
for(int a1=0;a1<3;a1++){
for(int a2=0;a2<3;a2++){
if(s1.now_position[a1][a2]!=s2.now_position[a1][a2]){
return false;
}
}
}
return true;
}
}
package ce;
public class test {
public static void main(String[] args) {
A_star_ d11=new A_star_();
}
}
思路概括
将九宫格每次移动后的状态都看做是一个对象,对九宫格移动步数的处理就转化为了,在多个对象中寻找适合条件的对象输出每一个对象的九宫格状态,对于已走过的九宫格状态可以用父结点进行存储,最后再将所有的父节点取出作为路径即可,在假设九宫格移动的函数中,选取坐标合法的九宫格状态加入队列进行排序,将每个对象按价值由低到高进行排序,就可以找到最小代价的路径了。