人工智能实验一,任课老师申冬苏。
个人总结:一个很简单的BFS问题,其他另外的算法可以自己尝试,这里只给最简单的BFS算法。
下面是八数码的类,使用的是JAVA语言:
实现过程很简单,定义方向链表,然后0-4下标表示左上右下四方向,不能往回走。
因此只需要方向下标相减不等于2即可,然后用结构体保存方向,路径等。
package Solutions.Homework;
import StructNode.MyTuple;
import java.util.*;
public class EightDigital {
//数码运动的方向
//the directions of number
public List<int[]>dir = new ArrayList<>();
private String ans = "";
private char[][] ep;
public EightDigital(){
dir.add(new int[]{0, -1});
dir.add(new int[]{-1, 0});
dir.add(new int[]{0, 1});
dir.add(new int[]{1, 0});
}
public String path(String[] source, String[] dest){
int n = source.length, m = source[0].length();
this.ep = new char[n][m];
char[][] p = new char[n][m];
//data initialization
for(int i = 0;i < n; i++){
p[i] = source[i].toCharArray();
this.ep[i] = dest[i].toCharArray();
}
//to decide whether it is reachable
System.out.println("source:" + Arrays.deepToString(p));
System.out.println("dest: " + Arrays.deepToString(ep));
if(!isArrived(source, dest)) return "No Way From Source to Dest";
for(int i = 0; i < n;i++){
for(int j = 0; j < m;j++){
if(p[i][j] == '0'){
//开始搜索
//start find answer
bfs(p, i, j, n, m);
break;
}
}
}
return ans;
}
/*
* input:数码的二维数组,开始搜索的坐标点,以及长度
* progress:使用广度优先搜索搜索能够实现的路径
* */
private void bfs(char[][] p, int x, int y, int n, int m){
//bfs使用队列,tuple包含坐标,上次经过的方向,路径,以及对应的数码。
//bfs need queue, the tuple contains points, last direction, path, and the corresponding number
Deque<MyTuple<int[], String, char[][]>>dq = new ArrayDeque<>();
dq.addLast(new MyTuple<>(new int[]{x, y ,-10}, "", p));
while(!dq.isEmpty()){
var t = dq.pollFirst();
//满足条件即可跳出循环
//if we look for the answer
if(Arrays.deepEquals(t.getThird(), ep)){
ans = t.getSecond();
System.out.println(ans.length());
break;
}
for(int i = 0;i < dir.size();i++){
//不能往返回的方向跑
//prohibit to go back
if(Math.abs(t.getFirst()[2] - i) == 2) continue;
int xi = t.getFirst()[0] + dir.get(i)[0], yi = t.getFirst()[1] + dir.get(i)[1];
//不能越界
//prohibit out of the verge
if(xi < 0 || xi >= n || yi < 0 || yi >= m) continue;
//System.out.println(t.getFirst()[0]+" "+xi+" "+t.getFirst()[1]+" "+yi);
//时刻交换数码的值
//swap the value of number all the time
char[][] k = getP(t.getThird(), n, m);
var temp = k[t.getFirst()[0]][t.getFirst()[1]];
k[t.getFirst()[0]][t.getFirst()[1]] = k[xi][yi];
k[xi][yi] = temp;
dq.addLast(new MyTuple<>(new int[]{xi, yi, i}, t.getSecond() + String.valueOf(i), k));
}
}
}
/*
* 复制一个中间变量,防止引用
* */
private char[][] getP(char[][] p, int n, int m){
char[][] k = new char[n][m];
//copy an obj to using
for(int i = 0;i < n;i++){
System.arraycopy(p[i], 0, k[i], 0, m);
}
return k;
}
private boolean isArrived(String[] source, String[] dest){
StringBuilder s = new StringBuilder();
StringBuilder d = new StringBuilder();
for(int i = 0;i < source.length;i++){
s.append(source[i]);
d.append(dest[i]);
}
int cnts = 0, cntd = 0;
//使用实验指导书上的方法判断是否可达
//to decide whether it is reachable by formula.
for(int i = 0;i < s.length();i++){
for(int j = i - 1 ;j >= 0;j--){
if(s.charAt(j) == '0' || d.charAt(j) == '0') continue;
cnts = s.charAt(j) < s.charAt(i) ? cnts : cnts + 1;
cntd = d.charAt(j) < d.charAt(i) ? cntd : cntd + 1;
}
}
return (cntd & 1) == (cnts & 1);
}
}
结构体的类:
package StructNode;
public class MyTuple<A, B, C> {
private A first;
private B second;
private C third;
public MyTuple(A first, B second, C third) {
this.first = first;
this.second = second;
this.third = third;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
public C getThird() {
return third;
}
public void setFirst(A first) {
this.first = first;
}
public void setSecond(B second) {
this.second = second;
}
public void setThird(C third) {
this.third = third;
}
}
使用如下:
package org.example;
import Solutions.BPFace.BTTrain;
import Solutions.Homework.EightDigital;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
EightDigital eightDigital = new EightDigital();
String[] dest = new String[3];
String[] source = new String[3];
for(int i = 0;i < 3;i++){
dest[i] = scanner.next();
}
for(int i = 0;i < 3;i++){
source[i] = scanner.next();
}
System.out.println(eightDigital.path(dest, source));
}
}
运行结果如下:
可以看到需要28步,下面字符串就是路径,路径0-4表示左上右下。