文章目录
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