隐式图的搜索(A*算法)

method类

简介:该类主要存放解决九宫重排中的问题的方法。

public class method implements Comparable{
    private int[] num = new int[9];
    private int F;                //估计函数f(n):从起始状态到目标的最小估计值
    private int G;                    //g(n):当前的深度,即走到当前状态的步骤
    private int H;            //启发函数 h(n):到目标的最小估计(记录和目标状态有多少个数不同)
    private method parent;            //当前状态的父状态
    private ArrayList<method> answer = new ArrayList<method>();    //保存最终路径
    public int[] getNum() {
        return num;
    }
    public void setNum(int[] num) {
        this.num = num;
    }
    public int getG() {
        return G;
    }
    public void setG(int G) {
        this.G = G;
    }
    public int getF() {
        return F;
    }
    public void setF(int F) {
        this.F = F;
    }
    public int getH() {
        return H;
    }
    public void setH(int H) {
        this.H = H;
    }
    public method getParent() {
        return parent;
    }
    public void setParent(method parent) {
        this.parent = parent;
    }

判断当前状态是否为目标状态:isaim()

/*
 * 判断当前状态是否为目标状态
 */
public boolean isaim(method aim){
    return Arrays.equals(getNum(), aim.getNum());
}

求估算函数f(n)的值

/*
 * 求估计函数f(n) = g(n)+h(n);
 */
public void numbers(method aim){
    int temp = 0;
    for(int i=0;i<9;i++){
        if(num[i]!=aim.getNum()[i])
            temp++;            //记录当前节点与目标节点差异的度量
    }
    this.setH(temp);
    if(this.getParent()==null){
        this.setG(0);    //初始化步数(深度)
    }else{
        this.G = this.parent.getG()+1;//记录步数
    }
    this.setF(this.getG()+this.getH());//返回当前状态的估计值
}

求逆序值:solution()

/*
 * 求逆序值并判断是否有解,逆序值同奇或者同偶才有解
 * return 有解:true 无解:false
 */
public boolean solution(method aim){
    int reverse = 0;
    for(int i=0;i<9;i++){
        for(int j=0;j<i;j++){//遇到0跳过
            if(num[j]>num[i] && num[j]!=0 && num[i]!= 0)
                reverse++;
            if(aim.getNum()[j]>aim.getNum()[i] && aim.getNum()[j]!=0 && aim.getNum()[i]!=0)
                reverse++;
        }
    }
    if(reverse % 2 == 0)
        return true;
    return false;
}

对每个子状态的f(n)排序:compareTo()

/*
 * 对每个子状态的f(n)进行由小到大排序
 * */
@Override
public int compareTo(Object o) {
	method c = (method) o;
    return this.F-c.getF();//默认排序为f(n)由小到大排序
}

返还0再九宫格的位置:getzero()

/*
 * @return 返回0在九宫格中的位置
 */
public int getzero(){
    int position = -1;
    for(int i=0;i<9;i++){
        if(this.num[i] == 0){
            position = i;
        }
    }
    return position;
}

去重:isRepear()

/*
 * 去重,当前状态不重复返回-1
 * @param open    状态集合
 * @return 判断当前状态是否存在于open表中
 */
public int isRepeat(ArrayList<method> open){
    for(int i=0; i<open.size(); i++){
        if(Arrays.equals(open.get(i).getNum(), getNum())){
            return i;
        }
    }
    return -1;
}

边界判定

上边界

/*
 * 上边界
 * 小于3(第一行)的不能上移
 */
public boolean up() {
    int position = getzero();
    if(position<=2){
        return false;
    }
    return true;
}

下边界

/*
 * 下边界
 * 大于6(第三行)的不能下移
 */
public boolean down() {
    int position = getzero();
    if(position>=6){
        return false;
    }
    return true;
}

左边界

/*
 * 左边界
 * 0,3,6(第一列)不能左移
 */
public boolean left() {
    int position = getzero();
    if(position%3 == 0){
        return false;
    }
    return true;
}

右边界

/*
 * 右边界
 * 2,5,8(第三列)不能右移
 */
public boolean right() {
    int position = getzero();
    if((position)%3 == 2){
        return false;
    } 
    return true;
}

移动:Move()

/*
 * 
 * @param move 8:上,2:下,4:左,6:右
 * @return 返回移动后的状态
 */
public method Move(int move){
	method temp = new method();
    int[] tempnum = (int[])num.clone();
    temp.setNum(tempnum);
    int position = getzero();    //0的位置
    int p=0;                            //与0换位置的位置
    switch(move){
        case 8:
            p = position-3;
            temp.getNum()[position] = num[p];
            break;
        case 2:
            p = position+3;
            temp.getNum()[position] = num[p];
            break;
        case 4:
            p = position-1;
            temp.getNum()[position] = num[p];
            break;
        case 6:
            p = position+1;
            temp.getNum()[position] = num[p];
            break;
    }
    temp.getNum()[p] = 0;
    return temp;
}

打印输出

3*3格式设定:print()

/*
 * 按照3*3格式输出
 */
public void print(){
    for(int i=0;i<9;i++){
        if(i%3 == 2){
            System.out.println(this.num[i]);
        }else{
            System.out.print(this.num[i]+"  ");
        }
    }
}

路径输出:printRoute()

/*
 * 将最终答案路径保存下来并输出
 */
public void printRoute(){
	method temp = null;
    int count = 0;
    temp = this;
    System.out.println("----------开始移动----------");
    while(temp!=null){
        answer.add(temp);
        temp = temp.getParent();
        count++;
    }
    for(int i=answer.size()-1 ; i>=0 ; i--){
        answer.get(i).print();
        System.out.println("--------------------");
    }
    System.out.println("最小移动步数:"+(count-1));
}

拓展节点的查重及插入:operation()

/**
 * 
 * @param open open表
 * @param close close表
 * @param parent 父状态
 * @param aim 目标状态
 */
public void operation(ArrayList<method> open,ArrayList<method> close,method parent,method aim){
    if(this.isRepeat(close) == -1){//不重复且不在close表中(这里可以进行改进,减少运行时间。)
        int position = this.isRepeat(open);//获取在open表中的位置
        if(position == -1){//如果也不在open表中
            this.parent = parent;//指明它的父状态
            this.numbers(aim);//计算它的估计值
            open.add(this);//把它添加进open表
        }else{//如果它在open表中
            if(this.getG() < open.get(position).getG()){//跟已存在的状态作比较,如果它的步数较少则是较优解
                open.remove(position);//把已经存在的相同状态替换掉
                this.parent = parent;
                this.numbers(aim);
                open.add(this);
            }
        }
    }
}

test类

简介:该类主要是对method类中方法的调用以及对目标状态是否达成的判定。

相应对象的创建及初始状态,目标状态的输入。

public class test {
	@SuppressWarnings("unchecked")
	public static void main(String args[]){
        ArrayList<method> open = new ArrayList<method>();
        ArrayList<method> close = new ArrayList<method>();
        method start = new method();
        method aim = new method();
        Scanner s = new Scanner(System.in);
        int Snum[] = new int[9];
        int Anum[] = new int[9];
        System.out.println("请输入初始状态:");
        for(int i = 0; i< 9; i++){
        	Snum[i] = s.nextInt();
        }
        System.out.println("请输入目标状态:");
        for(int j= 0; j< 9; j++){
        	Anum[j] = s.nextInt();
        }
        s.close();
        start.setNum(Snum);
        aim.setNum(Anum);
        long startTime=System.currentTimeMillis();

是否达到目标状态的判定

if(start.solution(aim)){//逆序值是否为同奇或同偶
            //初始化初始状态
            start.numbers(aim);//计算估算函数f(n)的值            
            open.add(start);//加入open表
            while(open.isEmpty() == false){
                Collections.sort(open);//按照f(n)的值排序
                method minpath = open.get(0);//从open表中取出最小估值的状态并移出open表
                open.remove(0);
                close.add(minpath);        
                if(minpath.isaim(aim)){//输出
                	minpath.printRoute();
                    long end=System.currentTimeMillis();
                    System.out.println("程序运行 "+ (end-startTime) +" ms");
                    System.exit(0);
                }
                int move;
                //由minpath状态进行扩展并加入到open表中
                //0的位置上移之后状态不在close和open中设定minpath为其父状态,并初始化f(n)估值函数
                if(minpath.up()){//可以上移的话
                    move = 8;//上移标记
                    method up = minpath.Move(move);//minpath的一个子状态
                    up.operation(open, close, minpath, aim);
                }
                //0的位置下移之后状态不在close和open中设定minpath为其父状态,并初始化f(n)估值函数
                if(minpath.down()){
                    move = 2;//下
                    method down = minpath.Move(move);
                    down.operation(open, close, minpath, aim);
                }
                //0的位置左移之后状态不在close和open中设定minpath为其父状态,并初始化f(n)估值函数
                if(minpath.left()){
                    move = 4;//左
                    method left = minpath.Move(move);
                    left.operation(open, close, minpath, aim);
                }
                //0的位置右移之后状态不在close和open中设定minpath为其父状态,并初始化f(n)估值函数
                if(minpath.right()){
                    move = 6;//右
                    method right = minpath.Move(move);
                    right.operation(open, close, minpath, aim);
                } 
            }
        }else 
            System.out.println("目标状态不可达。");
    }
}

运行截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

附:参考文献:A*寻路算法

网址:http://www.gamedev.net/reference/articles/article2003.asp

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值