隐式图的搜索问题
实验任务:
1)对九宫重排问题,建立图的启发式搜索求解方法;
2)用A*算法求解九宫重排问题。
实验要求:
3х3九宫棋盘,放置数码为1~8的8个棋子,棋盘中留有一个空格,空格周围的棋子可以移动到空格中,从而改变棋盘的布局。根据给定初始布局和目标布局,移动棋子从初始布局到达目标布局,求解移动步骤并输出。请设计算法,使用合适的搜索策略,在较少的空间和时间代价下找到最短路径。
启发式搜索求解方法
由于时间和空间资源的限制,穷举法只能解决一些状态空间很小的简单问题,而对于那些大状态空间的问题,穷举法就不能胜任,往往会导致“组合爆炸”。所以引入启发式搜索策略。启发式搜索就是利用启发性信息进行制导的搜索。它有利于快速找到问题的解。
由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零。所以,这个数码不同的位置个数便是标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息就可以指导搜索。即可以利用启发信息来扩展节点的选择,减少搜索范围,提高搜索速度。
启发函数设定。对于八数码问题,可以利用棋局差距作为一个度量。搜索过程中,差距会逐渐减少,最终为零,为零即搜索完成,得到目标棋局。
A*算法
a. 遍历 open list ,查找 F 值最小的节点,把它作为当前要处理的节点。
b. 把这个节点移到 close list 。
c. 对当前方格的 8 个相邻方格的每一个方格?
◆ 如果它是不可抵达的或者它在 close list 中,忽略它。否则,做如下操作。
◆ 如果它不在 open list 中,把它加入 open list ,并且把当前方格设置为它的父亲,记录该方格的 F , G 和 H 值。
◆ 如果它已经在 open list 中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更好,用 G 值作参考。更小的 G 值表示这是更好的路径。如果是这样,把它的父亲设置为当前方格,并重新计算它的 G 和 F 值。如果你的 open list 是按 F 值排序的话,改变后你可能需要重新排序。
d. 停止,当你
◆ 把终点加入到了 open list 中,此时路径已经找到了,或者
◆ 查找终点失败,并且 open list 是空的,此时没有路径。
保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。
代码实现
public boolean isSolvable(EightPuzzle target){
int reverse = 0;
for(int i=0;i<9;i++){
for(int j=0;j<i;j++){//遇到0跳过
if(nine[j]>nine[i] && nine[j]!=0 && nine[i]!= 0)
reverse++;
if(target.getNine()[j]>target.getNine()[i] && target.getNine()[j]!=0 && target.getNine()[i]!=0)
reverse++;
}
}
if(reverse % 2 == 0)
return true;
return false;
}
public int compareTo(Object o) {
EightPuzzle c = (EightPuzzle) o;
return this.f-c.getF();
}
public int getZeroPosition(){
int position = -1;
for(int i=0;i<9;i++){
if(this.nine[i] == 0){
position = i;
}
}
return position;
}
public int isContains(ArrayList<EightPuzzle> open){
for(int i=0; i<open.size(); i++){
if(Arrays.equals(open.get(i).getNine(), getNine())){
return i;
}
}
return -1;
}
public boolean isMoveUp() {
int position = getZeroPosition();
if(position<=2){
return false;
}
return true;
}
public boolean isMoveDown() {
int position = getZeroPosition();
if(position>=6){
return false;
}
return true;
}
public boolean isMoveLeft() {
int position = getZeroPosition();
if(position%3 == 0){
return false;
}
return true;
}
public boolean isMoveRight() {
int position = getZeroPosition();
if((position)%3 == 2){
return false;
}
return true;
}
public EightPuzzle moveUp(int move){
EightPuzzle temp = new EightPuzzle();
int[] tempnum = nine.clone();
temp.setNine(tempnum);
int position = getZeroPosition();
int p=0;
switch(move){
case 0:
p = position-3;
temp.getNine()[position] = nine[p];
break;
case 1:
p = position+3;
temp.getNine()[position] = nine[p];
break;
case 2:
p = position-1;
temp.getNine()[position] = nine[p];
break;
case 3:
p = position+1;
temp.getNine()[position] = nine[p];
break;
}
temp.getNine()[p] = 0;
return temp;
}
public void print(){
for(int i=0;i<9;i++){
if(i%3 == 2){
System.out.println(this.nine[i]);
}else{
System.out.print(this.nine[i]+" ");
}
}
}
public void printRoute(){
EightPuzzle temp = null;
int count = 0;
temp = this;
System.out.println("----------开始移动----------");
while(temp!=null){
shortpath.add(temp);
temp = temp.getParent();
count++;
}
for(int i=shortpath.size()-2 ; i>=0 ; i--){
System.out.println("第"+(shortpath.size()-i-1)+"步");
shortpath.get(i).print();
System.out.println("--------------------");
}
}
public void operation(ArrayList<EightPuzzle> open,ArrayList<EightPuzzle> close,EightPuzzle parent,EightPuzzle target){
if(this.isContains(close) == -1){
int position = this.isContains(open);
if(position == -1){
this.parent = parent;
this.celF(target);
open.add(this);
}else{
if(this.getG() < open.get(position).getG()){
open.remove(position);
this.celF(target);
open.add(this);
}
}
}
}
public static void main(String args[]) {
//定义open表
ArrayList<EightPuzzle> open = new ArrayList<EightPuzzle>();
ArrayList<EightPuzzle> close = new ArrayList<EightPuzzle>();
EightPuzzle start = new EightPuzzle();
EightPuzzle target = new EightPuzzle();
Scanner s = new Scanner(System.in);
int startarray[] = new int[9];
int targetarray[] = new int[9];
System.out.println("请输入初始状态:");
for (int i = 0; i < 9; i++) {
startarray[i] = s.nextInt();
}
System.out.println("请输入目标状态:");
for (int j = 0; j < 9; j++) {
targetarray[j] = s.nextInt();
}
s.close();
start.setNine(startarray);
target.setNine(targetarray);
start.celF(target);
open.add(start);
while (open.isEmpty() == false) {
Collections.sort(open);
EightPuzzle best = open.get(0);
open.remove(0);
close.add(best);
if (best.isTarget(target)) {
//输出
best.printRoute();
}
int move;
if (best.isMoveUp()) {
move = 0;
EightPuzzle up = best.moveUp(move);
up.operation(open, close, best, target);
}
if (best.isMoveDown()) {
move = 1;
EightPuzzle down = best.moveUp(move);
down.operation(open, close, best, target);
}
if (best.isMoveLeft()) {
move = 2;
EightPuzzle left = best.moveUp(move);
left.operation(open, close, best, target);
}
if (best.isMoveRight()) {
move = 3;
EightPuzzle right = best.moveUp(move);
right.operation(open, close, best, target);
}
}
}