隐式图的搜索问题 代码实现

代码具体实现如下:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Scanner;
public class Main implements Comparable {
    private int[] num = new int[9];
    //估值函数f(n):从起始状态到目标的最小估计值
    private int evaluation;
    //d(n):当前的深度,即走到当前状态的步骤
    private int depth;
    //启发函数 h(n):到目标的最小估计(记录和目标状态有多少个数不同)
    private int misposition;
    //当前状态的父状态
    private Main parent;
    //保存最终路径
    private ArrayList<Main> answer = new ArrayList<Main>();

    public int[] getNum() {
        return num;
    }

    public void setNum(int[] num) {
        this.num = num;
    }

    public int getDepth() {
        return depth;
    }

    public void setDepth(int depth) {
        this.depth = depth;
    }

    public int getEvaluation() {
        return evaluation;
    }

    public void setEvaluation(int evaluation) {
        this.evaluation = evaluation;
    }

    public int getMisposition() {
        return misposition;
    }

    public void setMisposition(int misposition) {
        this.misposition = misposition;
    }

    public Main getParent() {
        return parent;
    }

    public void setParent(Main parent) {
        this.parent = parent;
    }

    /**
     * 判断当前状态是否为目标状态
     *
     * @param target
     * @return
     */
    public boolean isTarget(Main target) {
        return Arrays.equals(getNum(), target.getNum());
    }

    /**
     * 求估值函数f(n) = g(n)+h(n);
     * 初始化状态信息
     *
     * @param target
     */
    public void init(Main target) {
        int temp = 0;
        for (int i = 0; i < 9; i++) {
            if (num[i] != target.getNum()[i])
                //记录当前节点与目标节点差异的度量
                temp++;
        }
        this.setMisposition(temp);
        if (this.getParent() == null) {
            //初始化步数(深度)
            this.setDepth(0);
        } else {
            //记录步数
            this.depth = this.parent.getDepth() + 1;
        }
        //返回当前状态的估计值
        this.setEvaluation(this.getDepth() + this.getMisposition());
    }

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

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

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

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

    /**
     * 一维数组
     *
     * @return
     */
    public boolean isMoveUp() {
        int position = getZeroPosition();
        if (position <= 2) {
            return false;
        }
        return true;
    }

    /**
     * @return
     */
    public boolean isMoveDown() {
        int position = getZeroPosition();
        if (position >= 6) {
            return false;
        }
        return true;
    }

    /**
     * @return
     */
    public boolean isMoveLeft() {
        int position = getZeroPosition();
        if (position % 3 == 0) {
            return false;
        }
        return true;
    }

    /**
     * @return
     */
    public boolean isMoveRight() {
        int position = getZeroPosition();
        if ((position) % 3 == 2) {
            return false;
        }
        return true;
    }

    /**
     * @param
     * @return 返回移动后的状态
     */
    public Main moveUp(int move) {
        Main temp = new Main();
        int[] tempnum = num.clone();
        temp.setNum(tempnum);
        //0的位置
        int position = getZeroPosition();
        //与0换位置的元素的位置
        int p = 0;
        switch (move) {
            case 0:
                p = position - 3;
                temp.getNum()[position] = num[p];
                break;
            case 1:
                p = position + 3;
                temp.getNum()[position] = num[p];
                break;
            case 2:
                p = position - 1;
                temp.getNum()[position] = num[p];
                break;
            case 3:
                p = position + 1;
                temp.getNum()[position] = num[p];
                break;
        }
        temp.getNum()[p] = 0;
        return temp;
    }

    /**
     * 按照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] + "  ");
            }
        }
    }

    /**
     * 将最终答案路径保存下来并输出
     */
    public void printRoute() {
        Main 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));
    }

    /**
     * @param open   open表
     * @param close  close表
     * @param parent 父状态
     * @param target 目标状态
     */
    public void operation(ArrayList<Main> open, ArrayList<Main> close, Main parent, Main target) {
        //判断是否在close表中
        if (this.isContains(close) == -1) {
            //获取在open表中的位置
            int position = this.isContains(open);
            //判断是否在open表中
            if (position == -1) {
                //指明它的父状态
                this.parent = parent;
                //计算它的估计值
                this.init(target);
                //把它添加进open表
                open.add(this);
            } else {
                //跟已存在的状态作比较,如果它的步数较少则是较优解
                if (this.getDepth() < open.get(position).getDepth()) {
                    //把已经存在的相同状态替换掉
                    open.remove(position);
                    this.parent = parent;
                    this.init(target);
                    open.add(this);
                }
            }
        }
    }

    public static void main(String args[]) {
        //定义open表
        ArrayList<Main> open = new ArrayList<Main>();
        //定义close表
        ArrayList<Main> close = new ArrayList<Main>();
        Main start = new Main();
        Main target = new Main();

        Scanner s = new Scanner(System.in);
        int stnum[] = new int[9];
        int tanum[] = new int[9];
        System.out.println("请输入初始状态:");
        for (int i = 0; i < 9; i++) {
            stnum[i] = s.nextInt();
        }
        System.out.println("请输入目标状态:");
        for (int j = 0; j < 9; j++) {
            tanum[j] = s.nextInt();
        }
        s.close();

        start.setNum(stnum);
        target.setNum(tanum);
        long startTime = System.currentTimeMillis();
        if (start.isSolvable(target)) {
            //初始化初始状态
            start.init(target);
            open.add(start);
            while (open.isEmpty() == false) {
                //按照evaluation的值排序
                Collections.sort(open);
                //从open表中取出最小估值的状态并移出open表
                Main best = open.get(0);
                open.remove(0);
                close.add(best);

                if (best.isTarget(target)) {
                    //输出
                    best.printRoute();
                    long end = System.currentTimeMillis();
                    System.out.println("程序运行 " + (end - startTime) + " ms");
                    System.exit(0);
                }

                int move;
                //由best状态进行扩展并加入到open表中
                //0的位置上移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
                //判断是否可以上移
                if (best.isMoveUp()) {
                    //上移标记
                    move = 0;
                    //best的一个子状态
                    Main up = best.moveUp(move);
                    up.operation(open, close, best, target);
                }
                //0的位置下移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
                if (best.isMoveDown()) {
                    move = 1;
                    Main down = best.moveUp(move);
                    down.operation(open, close, best, target);
                }
                //0的位置左移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
                if (best.isMoveLeft()) {
                    move = 2;
                    Main left = best.moveUp(move);
                    left.operation(open, close, best, target);
                }
                //0的位置右移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
                if (best.isMoveRight()) {
                    move = 3;
                    Main right = best.moveUp(move);
                    right.operation(open, close, best, target);
                }
            }
        } else {
            System.out.println("目标状态不可达");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值