目录
二分查找非递归算法实现
分治算法解决汉诺塔问题
动态规划算法解决01背包问题
暴力匹配算法解决字符串匹配问题
KMP算法解决字符串匹配问题
贪心算法解决集合覆盖问题
普里姆算法解决最短修路问题(最小生成树)
克鲁斯卡尔算法解决最短修路问题(最小生成树)
迪杰斯特拉算法解决最短路径问题
弗洛伊德算法解决最短路径问题
回溯算法解决骑士周游问题
二分查找非递归算法实现
public class BinarySearch {
public static void main(String[] args) {
int[] arr = { 1, 3, 8, 10, 11, 67, 100 };
int i = BinarySearch(arr, 1);
System.out.println("找到的下标为:" + i);
}
/**
* @param arr 待查找数组,arr是升序排列
* @param target 需要查找的数
* @return 查找的数的下标,-1表示没找到
*/
public static int BinarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
}
分治算法解决汉诺塔问题
public class HanoiTower {
public static void main(String[] args) {
hanoiTower(5, 'a', 'b', 'c');
}
public static void hanoiTower(int num, char a, char b, char c) {
if (num == 1) {
System.out.println("第" + num + "个盘从" + a + "->" + c);
} else {
// 把上面的num-1个盘移动到b,然后把第num个盘移动到c,然后把num-1个盘移动到c
hanoiTower(num - 1, a, c, b);
System.out.println("第" + num + "个盘从" + a + "->" + c);
hanoiTower(num - 1, b, a, c);
}
}
}
动态规划算法解决01背包问题
public class BagProblem {
public static void main(String[] args) {
int[] w = { 1, 4, 3 };// 物品的重量
int[] val = { 1500, 3000, 2000 };// 物品的价值
int m = 4;// 背包的容量
int n = val.length;// 物品的个数
// 创建二维数组,v[i][j]表示前i个物品能够装入容量为j的背包中的最大价值
int[][] v = new int[n + 1][m + 1];
// 创建一个二维数组,path[i][j]表示放入商品的 情况
int[][] path = new int[n + 1][m + 1];
// 初始化第一行和第一列,在本程序中可以不写,默认为0,但是写了就表示我们有处理
for (int i = 0; i < v.length; i++) {
v[i][0] = 0;// 将第一列设置为0
}
for (int i = 0; i < v[0].length; i++) {
v[0][i] = 0;// 将第一行设置为0
}
// 动态规划处理
for (int i = 1; i < v.length; i++) {// 从第一行开始处理,不处理第0行
for (int j = 1; j < v[i].length; j++) {// 从第一例开始处理,不处理第0列
if (w[i - 1] > j) {// 因为i是从1开始的,w[0]表示第一个物品的重量,所以要w[i-1]
v[i][j] = v[i - 1][j];
} else {
// v[i][j] = Math.max(v[i - 1][j], val[i - 1] + v[i - 1][j - w[i - 1]]);// val[i]也要改成val[i-1],w[i]也要改成w[i-1]
if (v[i - 1][j] > val[i - 1] + v[i - 1][j - w[i - 1]]) {
v[i][j] = v[i - 1][j];
path[i][j] = 1;
} else {
v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
path[i][j] = 1;
}
}
}
}
// 输出v
for (int i = 0; i < v.length; i++) {
for (int j = 0; j < v[i].length; j++) {
System.out.print(v[i][j] + " ");
}
System.out.println();
}
// 输出最后我们放入的商品
// 此时我们需要的是最后放入的情况
int i = path.length - 1;
int j = path[0].length - 1;
while (i > 0 && j > 0) {
if (path[i][j] == 1) {
System.out.println("第" + i + "个商品放入背包");
j -= w[i - 1];
}
i--;
}
}
}
暴力匹配算法解决字符串匹配问题
public class ViolenceMatch {
public static void main(String[] args) {
String s1 = "fdjslkfjasd;lkfjhoifhasdlkfmjsdklfjjujsdfo;as";
String s2 = "fjj";
int violenceMatch = violenceMatch(s1, s2);
System.out.println(violenceMatch);
}
// 暴力匹配算法
public static int violenceMatch(String s1, String s2) {
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int length = c1.length;
int length2 = c2.length;
int i = 0;
int j = 0;
while (i < length && j < length2) {
if (c1[i] == c2[j]) {
i++;
j++;
} else {
i = i - (j - 1);
j = 0;
}
}
if (j == length2) {
return i - j;
} else {
return -1;
}
}
}
KMP算法解决字符串匹配问题
public class KMPAlgorithm {
public static void main(String[] args) {
String s1 = "BBC ABCDAB ABCDABCDABDE";
String s2 = "ABCDABD";
int[] kmpNext = kmpNext(s2);
System.out.println(Arrays.toString(kmpNext));
int index = kmp(s1, s2, kmpNext);
System.out.println("index=" + index);
}
// 先来一个方法,获取到一个字符串(子串)的部分匹配值
public static int[] kmpNext(String string) {
// 创建一个数组,大小为string.length
int[] next = new int[string.length()];
next[0] = 0;// 如果字符串只有一个字符,那部分匹配值就是0;
for (int i = 1, j = 0; i < next.length; i++) {
while (j > 0 && string.charAt(i) != string.charAt(j)) {
j = next[j - 1];
}
if (string.charAt(i) == string.charAt(j)) {
j++;
}
next[i] = j;
}
return next;
}
// kmp算法
public static int kmp(String s1, String s2, int[] next) {
for (int i = 0, j = 0; i < s1.length(); i++) {
while (j > 0 && s1.charAt(i) != s2.charAt(j)) {
j = next[j - 1];
}
if (s1.charAt(i) == s2.charAt(j)) {
j++;
}
if (j == s2.length()) {
return i - (j - 1);
}
}
return -1;
}
}
贪心算法解决集合覆盖问题
public class GreedyAlgorithm {
public static void main(String[] args) {
// 创建广播电台,放到Map中
HashMap<String, HashSet<String>> broadcasts = new HashMap<String, HashSet<String>>();
HashSet<String> hashSet1 = new HashSet<String>();
hashSet1.add("北京");
hashSet1.add("上海");
hashSet1.add("天津");
HashSet<String> hashSet2 = new HashSet<String>();
hashSet2.add("广州");
hashSet2.add("北京");
hashSet2.add("深圳");
HashSet<String> hashSet3 = new HashSet<String>();
hashSet3.add("成都");
hashSet3.add("上海");
hashSet3.add("杭州");
HashSet<String> hashSet4 = new HashSet<String>();
hashSet4.add("上海");
hashSet4.add("天津");
HashSet<String> hashSet5 = new HashSet<String>();
hashSet5.add("杭州");
hashSet5.add("大连");
broadcasts.put("k1", hashSet1);
broadcasts.put("k2", hashSet2);
broadcasts.put("k3", hashSet3);
broadcasts.put("k4", hashSet4);
broadcasts.put("k5", hashSet5);
HashSet<String> allAreas = new HashSet<String>();// 这个存放所有的地区
allAreas.addAll(hashSet1);
allAreas.addAll(hashSet2);
allAreas.addAll(hashSet3);
allAreas.addAll(hashSet4);
allAreas.addAll(hashSet5);
System.out.println(allAreas);
ArrayList<String> selects = new ArrayList<String>();// 这里创建一个ArrayList用来存放选上的电台
HashSet<String> tempSet = new HashSet<String>();// 这里 一个HashSet用来临时存储遍历过程中的某个电台所覆盖的地区
String maxKey = null;// 定义一个maxKey用来保存遍历过程中能够覆盖最多的未被覆盖地区的电台
while (allAreas.size() != 0) {// allAreas里面的地区是不断减少的
maxKey = null;// 置空maxKey
for (String k : broadcasts.keySet()) {
tempSet.clear();// 置空临时的存储某个电台覆盖地区的这个tempSet
HashSet<String> areas = broadcasts.get(k);// 遍历过程中的某个电台可以覆盖的地区保存下来
tempSet.addAll(areas);// 用我们定义好的tempSet变量存储地区
tempSet.retainAll(allAreas);// 筛选出这个电台覆盖地区与未被覆盖地区的交集
if (tempSet.size() > 0 &&
// 表示maxKey还没有选到或者 现在这个k电台所覆盖的地区数大于之前选到的maxKey所覆盖的地区数,此时替换maxKey
(maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())) {
maxKey = k;
}
// 每进行依次for循环,这里的 tempSet也要置空,同样写在for循环刚开始的时候
}
if (maxKey != null) {
selects.add(maxKey);// 此时maxKey电台真正的被选上,这里加进去然后会把他所覆盖的地区从未覆盖的地区删除了
allAreas.removeAll(broadcasts.get(maxKey));
}
// 此时要把maxKey置空,以防止下一次遍历时,本来已经要结束了,maxKey就是null,但是没有置空,就会又加进去一个电台
// 然而置空的操作写在while循环刚开始的地方。
}
System.out.println(selects);
}
}
普里姆算法解决两点间最短路径问题
三个链表分别存储:是否存在该节点;该节点与已选区域的边的长度;父节点
public class PrimAlgorithm {
public static void main(String[] args) {
char[] data = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
int verxs = data.length;
int[][] weight = new int[][] { { 10, 5, 7, 10, 10, 10, 2 }, { 5, 10, 10, 9, 10, 10, 3 },
{ 7, 10, 10, 10, 8, 10, 10 }, { 10, 9, 10, 10, 10, 4, 10 }, { 10, 10, 8, 10, 10, 5, 4 },
{ 10, 10, 10, 4, 5, 10, 6 }, { 2, 3, 10, 10, 4, 6, 10 }, };
MGraph mGraph = new MGraph(verxs);
MinTree minTree = new MinTree();
minTree.createGraph(mGraph, verxs, data, weight);
minTree.show(mGraph);
minTree.prim(mGraph, 0);
}
}
//创建最小生成树
class MinTree {
/**
* @param graph 图对象
* @param verxs 图的顶点个数
* @param data 图的各个顶点的值
* @param weight 图的邻接矩阵
*/
public void createGraph(MGraph graph, int verxs, char[] data, int[][] weight) {
for (int i = 0; i < verxs; i++) {
graph.data[i] = data[i];
for (int j = 0; j < verxs; j++) {
graph.weight[i][j] = weight[i][j];
}
}
}
// 显示图的邻接矩阵
public void show(MGraph graph) {
for (int[] link : graph.weight) {
System.out.println(Arrays.toString(link));
}
}
// 编写prim算法,获得最小生成树
/**
* @param graph 邻接矩阵
* @param v 表示从图的第几个顶点开始生成
*/
public void prim(MGraph graph, int v) {
int[] visited = new int[graph.verxs];// 用一个一维数组来表示节点是否被访问过了,0表示没有访问,1表示访问过了
// 刚开始时我们传进来一个节点,先把这个节点设置成已经访问过的
visited[v] = 1;
// 定义一个边最小为10(因为我的邻接矩阵中的最大的就是10,这个最小边不可能是10,所以我这里的10就表示的这两个点不连接)
int minWeight = 10;
// 定义两个int型的数字来表示顶点的位置
int h1 = -1;
int h2 = -1;
// 此时我们知道,普里姆算法中,如果有n个节点,那将会产生n-1条边,所以:
for (int k = 0; k < graph.verxs - 1; k++) {
// 查找被访问过的节点和没有被访问的节点之间最短的那一条边
for (int i = 0; i < graph.verxs; i++) {// 表示访问过的节点,if()语句给出条件限制
for (int j = 0; j < graph.verxs; j++) {// 表示没有访问过的节点,if()语句给出条件限制
if (visited[i] == 1 && visited[j] == 0 && minWeight > graph.weight[i][j]) {
// 替换掉这个minWeight
minWeight = graph.weight[i][j];
// 此时要考虑记录这两个节点,所有定义两个节点,又因为要输出所以定义在for循环之外
h1 = i;
h2 = j;
}
}
}
// 此时必定有一个minWeight,我们输出这个边,和两个点
System.out.println("节点:" + graph.data[h1] + "和节点:" + graph.data[h2] + "之间权值最小,为:" + minWeight);
// 最后把找到的这个节点标记为访问过的
visited[h2] = 1;
// 重置用到的元素
minWeight = 10;
// 因为h1和h2在循环之外定义的所以不用重置,否则也要重置
}
}
}
class MGraph {
int verxs;// 表示节点个数
char[] data;// 存放节点上的字母(村庄)
int[][] weight;// 存放边,也就是邻接矩阵
public MGraph(int verxs) {
this.verxs = verxs;
data = new char[verxs];
weight = new int[verxs][verxs];
}
}
克鲁斯卡尔算法解决两点间最短路径问题
所有边排序,从小到大依次添加,不构成环的情况下连接所有的顶点
public class KruskalCase {
public static void main(String[] args) {
char[] vertexs = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
int matrix[][] = { { 0, 12, INF, INF, INF, 14, 16 }, { 12, 0, 10, INF, INF, 7, INF },
{ INF, 10, 0, 3, 5, 6, INF }, { INF, INF, 3, 0, 4, INF, INF }, { INF, INF, 5, 4, 0, 2, 8 },
{ 16, 7, 6, INF, 2, 0, 9 }, { 14, INF, INF, INF, 8, 9, 0 } };
KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);
kruskalCase.print();
EData[] edges = kruskalCase.getEdges();
System.out.println("排序前" + Arrays.toString(edges));
kruskalCase.sortEdges(edges);
System.out.println("排序后" + Arrays.toString(edges));
kruskalCase.kruskal();
}
private int edgeNum;// 边的个数
private char[] vertexs;// 顶点数组
private int[][] matrix;// 邻接矩阵
private static final int INF = 100;// 表示不能联通
public KruskalCase(char[] vertexs, int[][] matrix) {
// 初始化顶点数和边的个数
// this.vertexs = vertexs;
// this.matrix = matrix;
// 这里是复制拷贝的方式,就是在构造器中重新创建一个数组
int vlen = vertexs.length;
// 初始化顶点
this.vertexs = new char[vlen];
for (int i = 0; i < vertexs.length; i++) {
this.vertexs[i] = vertexs[i];
}
// 初始化边
this.matrix = new int[vlen][vlen];
for (int i = 0; i < vlen; i++) {
for (int j = 0; j < vlen; j++) {
this.matrix[i][j] = matrix[i][j];
}
}
// 统计边
for (int i = 0; i < vlen; i++) {
for (int j = i + 1; j < vlen; j++) {
if (this.matrix[i][j] != INF) {
edgeNum++;
}
}
}
}
// 打印邻接矩阵
public void print() {
for (int i = 0; i < vertexs.length; i++) {
for (int j = 0; j < vertexs.length; j++) {
System.out.print(matrix[i][j] + "\t");
}
System.out.println();
}
}
// 对边进行排序,冒泡排序
private void sortEdges(EData[] eDatas) {
for (int i = 0; i < eDatas.length - 1; i++) {
for (int j = 0; j < eDatas.length - 1 - i; j++) {
if (eDatas[j].weight > eDatas[j + 1].weight) {
EData temp = eDatas[j];
eDatas[j] = eDatas[j + 1];
eDatas[j + 1] = temp;
}
}
}
}
/**
* @param ch 顶点的值
* @return 返回ch顶点对应的下标,如果没有就返回-1
*/
private int getPosition(char ch) {
for (int i = 0; i < vertexs.length; i++) {
if (ch == vertexs[i]) {
return i;
}
}
return -1;
}
private EData[] getEdges() {
int index = 0;
EData[] edges = new EData[edgeNum];
for (int i = 0; i < vertexs.length; i++) {
for (int j = i + 1; j < vertexs.length; j++) {
if (matrix[i][j] != INF) {
edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);
}
}
}
return edges;
}
/**
* 获取下标为i的顶点的终点
*
* @param ends 数组就是记录了各个顶点对应的终点是哪个,ends数组是在遍历的过程中逐步形成的
* @param i 表示传入顶点对应的下标
* @return 返回下标i的顶点对应的终点的下标
*/
private int getEnd(int[] ends, int i) {
while (ends[i] != 0) {
i = ends[i];
}
return i;
}
public void kruskal() {
int index = 0; // 表示最后结果数组的索引
int[] ends = new int[edgeNum]; // 用来保存已有的最小生成树的每个顶点对应的顶点
EData[] rets = new EData[edgeNum];// 创建结果数组,保存最后的最小生成树
EData[] edges = getEdges();
System.out.println("图中有" + edges.length + "条边,集合为:" + Arrays.toString(edges));
// 首先排序(从小到大)
sortEdges(edges);
// 遍历edges数组,将边添加到最小生成树中,同时判断是否生成回路,如果每生成回路,就加到rets中
for (int i = 0; i < edgeNum; i++) {
int p1 = getPosition(edges[i].start);// 获取到当前边的第一个顶点
int p2 = getPosition(edges[i].end);// 获取到当前边的第二个顶点
int end1 = getEnd(ends, p1);// 获取p1对应的终点
int end2 = getEnd(ends, p2);// 获取p2对应的终点
if (end1 != end2) {// 没有构成回路
ends[end1] = end2;// 设置end1对应的终点为end2(在现有的最小生成树中)
rets[index++] = edges[i];// 这条边进入最后的结果数组中
}
}
// 统计并打印最小生成树
System.out.println("最小生成树为:");
for (int i = 0; i < index; i++) {
System.out.println(rets[i]);
}
}
}
//创建一个类,其对象实例就是一条边
class EData {
char start;
char end;
int weight;
public EData(char start, char end, int weight) {
super();
this.start = start;
this.end = end;
this.weight = weight;
}
@Override
public String toString() {
return "EData [<" + start + "," + end + ">=" + weight + "]";
}
}
迪杰斯特拉算法解决最短路径问题
public class DijkstraAlgorithm {
public static void main(String[] args) {
char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
int[][] matrix = new int[vertex.length][vertex.length];
final int N = 100;// 表示不可连接
matrix[0] = new int[] { N, 5, 7, N, N, N, 2 };
matrix[1] = new int[] { 5, N, N, 9, N, N, 3 };
matrix[2] = new int[] { 7, N, N, N, 8, N, N };
matrix[3] = new int[] { N, 9, N, N, N, 4, N };
matrix[4] = new int[] { N, N, 8, N, N, 5, 4 };
matrix[5] = new int[] { N, N, N, 4, 5, N, 6 };
matrix[6] = new int[] { 2, 3, N, N, 4, 6, N };
Graph graph = new Graph(vertex, matrix);
graph.showGraph();
graph.djs(6);
graph.showdjs();
}
}
class Graph {
private char[] vertex;// 顶点数组
private int[][] matrix;// 邻接矩阵
private VisitedVertex vv;// 已经访问的顶点的集合
public Graph(char[] vertex, int[][] matrix) {
this.vertex = vertex;
this.matrix = matrix;
}
//显示邻接矩阵
public void showGraph() {
for (int[] i : matrix) {
System.out.println(Arrays.toString(i) + " ");
}
}
//迪杰斯特拉算法的实现,index表示出发顶点对应的下标
public void djs(int index) {
vv = new VisitedVertex(vertex.length, index);
updata(index);// 更新index顶点到周围顶底的距离和前驱节点
for (int i = 1; i < vertex.length; i++) {
index = vv.updateArr();// 更新并返回新的访问节点
updata(index);// 更新index顶点到周围顶底的距离和前驱节点
}
}
//更新index下标顶点到周围顶点的距离和周围顶点的前驱节点
public void updata(int index) {
int len = 0;
// 遍历邻接矩阵的matrix[index]行
for (int j = 0; j < matrix[index].length; j++) {
len = vv.getDis(index) + matrix[index][j];
// 顶点j没有被访问过,并且这条路的举例小于之前的初始节点到j的举例
if (!vv.in(j) && len < vv.getDis(j)) {
vv.updataDis(j, len);
vv.updataPre(j, index);
}
}
}
//显示结果
public void showdjs() {
vv.show();
}
}
class VisitedVertex {
public int[] already_arr;// 记录各个顶点是否已经访问过,访问过为1,否则为0.初始为0;
public int[] pre_visited;// 对应每个顶点的前一个节点的下标,动态更新
public int[] dis;// 记录从初始节点到其他顶点的距离, 初始化为不连接,用100来表示,节点本身到本身的距离为0
public VisitedVertex(int length, int index) {
this.already_arr = new int[length];
this.pre_visited = new int[length];
this.dis = new int[length];
already_arr[index] = 1;
Arrays.fill(dis, 100);
dis[index] = 0;
}
//判断index节点是否已经被访问过了
public boolean in(int index) {
return already_arr[index] == 1;
}
//更新index节点到初始节点的距离为len
public void updataDis(int index, int len) {
dis[index] = len;
}
//跟新pre节点的前驱节点的下标为index
public void updataPre(int pre, int index) {
pre_visited[pre] = index;
}
//获取index节点到初始节点的距离
public int getDis(int index) {
return dis[index];
}
//继续选择并返回新的访问节点
public int updateArr() {
int min = 100, index = 0;
for (int i = 0; i < already_arr.length; i++) {
if (already_arr[i] == 0 && dis[i] < min) {
min = dis[i];
index = i;
}
}
already_arr[index] = 1;
return index;
}
//显示最后结果,就是三个数组的输出
public void show() {
System.out.println("+==================================+");
for (int i : already_arr) {
System.out.print(i + " ");
}
System.out.println();
for (int i : pre_visited) {
System.out.print(i + " ");
}
System.out.println();
for (int i : dis) {
System.out.print(i + " ");
}
System.out.println();
// 为了方便看最后结果
char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
int count = 0;
for (int i : dis) {
if (i != 100) {
System.out.print(vertex[count] + "-> " + i + " ");
} else {
System.out.println("N ");
}
count++;
}
System.out.println();
}
}
弗洛伊德算法解决最短路径问题
public class FloydAlgorithm {
public static void main(String[] args) {
char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
int[][] matrix = new int[vertex.length][vertex.length];
final int N = 100;// 表示不可连接
matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };
Graph graph = new Graph(7, vertex, matrix);
graph.floyd();
graph.show();
}
}
class Graph {
private char[] vertex;// 存放顶点
private int[][] dis;// 保存各个顶点出发到其他顶点之间的距离
private int[][] pre;// 保存到达目标节点的前驱节点的下标
public Graph(int length, char[] vertex, int[][] matrix) {
this.vertex = vertex;
this.dis = matrix;
this.pre = new int[length][length];// 这个需要初始化,一开始存放的前驱节点就是自己
for (int i = 0; i < length; i++) {
Arrays.fill(pre[i], i);
}
}
// 显示pre数组和dis数组
public void show() {
// 为了便于阅读
char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
for (int i = 0; i < dis.length; i++) {
for (int j = 0; j < dis.length; j++) {
System.out.print(vertex[pre[i][j]] + "\t\t");
}
System.out.println();
for (int j = 0; j < dis.length; j++) {
System.out.print("(" + vertex[i] + "到" + vertex[j] + "=" + dis[i][j] + ") ");
}
System.out.println();
System.out.println();
}
}
//弗洛伊德算法
public void floyd() {
int len = 0;
for (int k = 0; k < dis.length; k++) {// 对中间节点的遍历
for (int i = 0; i < dis.length; i++) {// 对初始节点的遍历
for (int j = 0; j < dis.length; j++) {// 对最终节点的遍历
len = dis[i][k] + dis[k][j];
if (len < dis[i][j]) {
dis[i][j] = len;
pre[i][j] = pre[k][j];// 更新前驱节点
}
}
}
}
}
}
回溯算法解决骑士周游问题
public class HouseChess {
public static void main(String[] args) {
System.out.println("骑士周游算法:");
X = 8;
Y = 8;
int row = 0;
int column = 0;
int[][] chessBoard = new int[X][Y];
visited = new boolean[X * Y];
long l1 = System.currentTimeMillis();
traver(chessBoard, row, column, 1);
long l2 = System.currentTimeMillis();
System.out.println("时间:" + (l2 - l1));
System.out.println("棋盘:");
for (int[] i : chessBoard) {
System.out.println(Arrays.toString(i));
}
}
private static int X;// 棋盘的列数
private static int Y;// 棋盘的行数
private static boolean visited[];// 表示是否被访问过
private static boolean finished;// 表示是否全部走完
/**
*
* @param chessBoard 棋盘
* @param row 马儿当前在第几行,从0开始
* @param column 马儿当前在第几列,从0开始
* @param step 第几步,初始位置为第一步
*/
public static void traver(int[][] chessBoard, int row, int column, int step) {
chessBoard[row][column] = step; // 定位初始位置为第一步
visited[row * X + column] = true; // 初始位置已经被访问
ArrayList<Point> next = next(new Point(column, row));
sort(next);
while (!next.isEmpty()) {
Point p = next.remove(0);
if (!visited[p.y * X + p.x]) {
traver(chessBoard, p.y, p.x, step + 1);
}
}
if (step < X * Y && !finished) {
chessBoard[row][column] = 0;
visited[row * X + column] = false;
} else {
finished = true;
}
}
//返回下一步可以走的位置,用一个ArrayList来表示
public static ArrayList<Point> next(Point point) {
ArrayList<Point> ps = new ArrayList<Point>();
Point p1 = new Point();
if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y - 1) >= 0) {
ps.add(new Point(p1));
}
// 判断马儿可以走6这个位置
if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y - 2) >= 0) {
ps.add(new Point(p1));
}
// 判断马儿可以走7这个位置
if ((p1.x = point.x + 1) < X && (p1.y = point.y - 2) >= 0) {
ps.add(new Point(p1));
}
// 判断马儿可以走0这个位置
if ((p1.x = point.x + 2) < X && (p1.y = point.y - 1) >= 0) {
ps.add(new Point(p1));
}
// 判断马儿可以走1这个位置
if ((p1.x = point.x + 2) < X && (p1.y = point.y + 1) < Y) {
ps.add(new Point(p1));
}
// 判断马儿可以走2这个位置
if ((p1.x = point.x + 1) < X && (p1.y = point.y + 2) < Y) {
ps.add(new Point(p1));
}
// 判断马儿可以走3这个位置
if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y + 2) < Y) {
ps.add(new Point(p1));
}
// 判断马儿可以走4这个位置
if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y + 1) < Y) {
ps.add(new Point(p1));
}
return ps;
}
//排序,非递减
public static void sort(ArrayList<Point> ps) {
ps.sort(new Comparator<Point>() {
public int compare(Point o1, Point o2) {
int count1 = next(o1).size();
int count2 = next(o2).size();
if (count1 < count2) {
return -1;
} else if (count1 == count2) {
return 0;
} else {
return 1;
}
}
});
}
}