马上要考人工智能课。。。 想起来之前写了一个贼水的A算法(不知道算不算A*)解八数码(或者是九宫格拼图?)
(感觉搜索的很慢,难道我代码实现有bug?)
先贴一波最终结果
5 4 1
6 7 0
2 8 3
5 4 1
6 7 3
2 8 0
5 4 1
6 7 3
2 0 8
5 4 1
6 0 3
2 7 8
5 4 1
0 6 3
2 7 8
0 4 1
5 6 3
2 7 8
4 0 1
5 6 3
2 7 8
4 1 0
5 6 3
2 7 8
4 1 3
5 6 0
2 7 8
4 1 3
5 0 6
2 7 8
4 1 3
0 5 6
2 7 8
4 1 3
2 5 6
0 7 8
4 1 3
2 5 6
7 0 8
4 1 3
2 0 6
7 5 8
4 1 3
0 2 6
7 5 8
0 1 3
4 2 6
7 5 8
1 0 3
4 2 6
7 5 8
1 2 3
4 0 6
7 5 8
1 2 3
4 5 6
7 0 8
1 2 3
4 5 6
7 8 0
allCost=370,depth=19
usedtime=12143ms
节点类
class state {
int id;
int fatherId;
int cost;
int x,y;
int depth;
Integer[][] m = new Integer[3][3];
state(Integer[][] m,int depth,int id,int fatherId) {
this.depth=depth;
this.cost=caculateCost();
this.m=m;
this.id=id;
this.fatherId=fatherId;
}
boolean isEqual(state k){
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
if(k.m[i][j]!=m[i][j])
return false;
}
}
return true;
}
void findZero() {
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
if(0==m[i][j]) {
x=i;
y=j;
}
}
}
}
int caculateCost() {
int value=9;
Integer[][] end ={{1,2,3}
,{4,5,6},
{7,8,0}};
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
if(m[i][j]==end[i][j])
value--;
}
}
return value+depth;
}
void print(){
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
System.out.print(m[i][j]+" ");
}
System.out.println("");
}
}
void copyTo(Integer[][] s) {
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++) {
s[i][j]=m[i][j];
}
}
}
然后是实现搜索的类
大概思路是根据空格位置的不断移动来产生不同的新状态(子节点),放入list里遍历,对每个节点估价,高得放前边先搜索,低的后搜索。
估价函数大概是这样
f(n)=g(n)+h(n)
启发函数h(n)用的是不在正确位置的数码的个数。
g(n)
是从初始结点到结点
n
的最小代价
public class Away {
ArrayList<state> openTable = new ArrayList<>();
ArrayList<state> closedTable = new ArrayList<>();
ArrayList<state> ansTable = new ArrayList<>();
state endState;
state firstState;
static long startTime;
static int id=0;
public static void main(String[] args) {
Away a= new Away();
Integer[][] end ={{1,2,3}
,{4,5,6},
{7,8,0}};
Integer[][] start ={{5,4,1}
,{6,7,0},
{2,8,3}};
a.endState = new state( end,-1,-1,-1);
a.firstState=new state(start,0,-1,-1);
a.openTable.add(a.firstState);
startTime= System.currentTimeMillis(); //程序开始记录时间
a.expand(a.firstState);
while(a.openTable.size()!=0) {
a.expand(a.openTable.get(0));
}
System.out.println("failed");
}
void addNode(state node) {
if(node.isEqual(endState)) {
long endTime = System.currentTimeMillis(); //程序结束记录时间
long TotalTime = endTime - startTime;
int fatherId=node.fatherId;
ansTable.add(node);
for(int i=0;i<closedTable.size();i++) {
if(closedTable.get(i).id==fatherId) {
ansTable.add(0,closedTable.get(i));
if(closedTable.get(i).fatherId==-1) {
break;
}
else {
fatherId=closedTable.get(i).fatherId;
}
i=0;
}
}
ansTable.add(0,firstState);
int allCost=0;
for(int i=0;i<ansTable.size();i++) {
ansTable.get(i).print();
allCost=ansTable.get(i).cost+allCost;
System.out.println();
}
System.out.println("allCost="+allCost+",depth="+node.depth);
System.out.println("usedtime="+TotalTime+"ms");
System.exit(0);
}
if(isContains(closedTable, node)){
return;
}
for(int i=0;i<openTable.size();i++) {
if(openTable.get(i).isEqual(node)) {
if(openTable.get(i).cost<=node.cost)
return;
else
openTable.remove(node);
}
}
if(!isContains(openTable, node)){
for(int i=0;i<openTable.size();i++) {
if(openTable.get(i).cost>=node.cost) {
openTable.add(i, node);
return;
}
}
openTable.add(node);
}
}
void expand(state node){
closedTable.add(node);
openTable.remove(node);
node.findZero();
int x=node.x,y=node.y;
if(x+1!=3) {
Integer[][] n=new Integer[3][3];
node.copyTo(n);
n[x][y]=n[x+1][y];
n[x+1][y]=0;
int dep=node.depth;
state newNode = new state(n,dep+1,id,node.id);
id++;
addNode(newNode);
}
if(x-1!=-1) {
Integer[][] n=new Integer[3][3];
node.copyTo(n);
n[x][y]=n[x-1][y];
n[x-1][y]=0;
int dep=node.depth;
state newNode = new state(n,dep+1,id,node.id);
id++;
addNode(newNode);
}
if(y-1!=-1) {
Integer[][] n=new Integer[3][3];
node.copyTo(n);
n[x][y]=n[x][y-1];
n[x][y-1]=0;
int dep=node.depth;
state newNode = new state(n,dep+1,id,node.id);
id++;
addNode(newNode);
}
if(y+1!=3) {
Integer[][] n=new Integer[3][3];
node.copyTo(n);
n[x][y]=n[x][y+1];
n[x][y+1]=0;
int dep=node.depth;
state newNode = new state(n,dep+1,id,node.id);
id++;
addNode(newNode);
}
}
boolean isContains(ArrayList<state> state,state s) {
for(int i=0;i<state.size();i++) {
if(state.get(i).isEqual(s))
return true;
}
return false;
}
}
我觉得应该满足A*算法的条件
h
*(n)
是从结点
n
到达目标结点的最优路径的代价值,有多个目标结点时取其代价最小者
对
A
算法增加如下限制:
1:ni,nj是任意两个结点必有:C(ni,nj)>ε>0
2:h(n)是h*(n)的下界,即对任意结点都有
h(n)<h*(n)
则称此算法为A*算法
条件1满足,条件2应该是满足的,我用的启发函数估计代价应该比实际代价更高。
//为啥代码会显示两遍 头一回写就出现这种BUG 差评。。。。