阅读前准备
建议先看这篇文章同一个世界游戏 算法破解
改进思路
对于前篇文章(同一个世界游戏 算法破解)的Node类是通过Map<Integer, Integer>的对象来记录之前的走过的位置,这占用了大量的内存空间,检查的效率也低;节点的节点值等于父节点的值加本身的值(long childValue = parent.getValue() + (long) ),但是针对这个游戏(编码保存方式)而言,是否有可能有更好的方式
对以上两点考虑得到了更好的解决方式
重复位置检查
该游戏的状态是以二进制的方式保存的,经过的点对应的位标志为1,否则为0,也就是说任意一个节点的值实际上就已经保存了它所经过点,所以它的子节点只要检查节点值的二进制对应的位是否为1,即可知道是否走过该点
// 未经过该点
private boolean notPassed(long oldPosition, int index) {
return (oldPosition >> index & 1) == 0;
}
这样就节省了大量的时间和内存空间
节点值求和
有了上面的严谨检查,确保了子节点不会走过重复的点,这意味着一个节点值的二进制不会在相同的位上重复出现1的情况,也就是没有进位的情况,这样就可以把原来的加法运算改为或运算
long childValue = parent.getValue() | getValue(childIndex);
但是原本的加法也不可能会出现进位的情况,我想这并没有减少多少时间
其它问题
PathUtils类生成路径的时候可能是闭合路径但是还没有达到指定的路径深度,会造成死循环
重构NodeTree类的代码
代码
Node.java
public class Node {
private Node parent; // 父节点
private long value; // 当前路径值
private int row; // 当前节点的行
private int col; // 当前节点的列
private int index; // 起点序号
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
NodeTree.java
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class NodeTree {
private int[][] state; // 盘面
private int row, col; // 二维数组行、列
private long target; // 目标状态值
private Node[] solveNodes; // 解决路径
private List<Map<Long, Node>> nodes; // 所有路径
private Deque<Node> deque; // 可能路径
private long realSum; // 实际路径数量
public NodeTree(int[][] state, int[][] startPoint, long target) {
this.state = state;
this.target = target;
this.row = state.length;
this.col = state[0].length;
nodes = new ArrayList<>(startPoint.length);
for (int i = 0; i < startPoint